前段时间做项目优化,线上接口突然频繁超时,折腾半天才摸透mysql索引怎么用,全是实打实踩坑试出来的操作。
当时接手的是一个用户订单查询接口,数据量涨到了八十多万,原本秒出的接口,突然延迟到三五秒,高峰期直接超时报错。测试环境复现完全没问题,唯独线上卡顿,排查半天,发现是前期建表时乱加索引导致的问题。
最开始的认知特别片面,觉得索引建得越多,查询速度就越快,于是几乎给表里所有查询相关字段都加了索引,包括订单状态、创建时间、用户ID、支付金额一堆字段。
这就是第一个大坑。索引不是越多越好,多余的索引会严重拖慢写入速度。
线上订单表是高频写入表,每秒都有新订单生成、订单状态更新,大量冗余索引让每次增删改操作,都要额外维护一堆无效索引,直接拖垮了数据库性能,查询自然跟着变慢。
mysql索引怎么用:筛选有效建索引字段
折腾好久才搞明白,索引只服务于WHERE、ORDERBY、GROUPBY后的查询字段,其余字段完全没必要建。当时逐一排查接口SQL,发现日常业务查询,永远只固定用到用户ID和创建时间两个筛选条件,其余字段极少单独查询。
于是直接删掉表里所有多余的单列索引,只保留user_id和create_time两个核心查询字段的索引,同时删掉了长期闲置的复合索引。改动完成后,线上接口延迟直接降到几十毫秒,超时问题彻底消失。
还有个很容易忽略的点,复合索引的使用顺序绝对不能乱。之前为了适配多条件查询,建过一个(order_status,create_time)的复合索引,结果业务SQL永远是先查时间、再筛状态,索引完全失效,相当于白建。
字段顺序错,索引直接废。
mysql索引怎么用:贴合业务写复合索引
后来调整了复合索引结构,严格按照业务SQL的查询顺序,改成(create_time,order_status),贴合真实查询逻辑,原本需要全表扫描的复杂查询,直接命中索引,扫描行数缩减了九成以上。
这里还有个实测细节,低频更新、高频查询的字段最适合建索引,反之高频更新、极少查询的字段,建索引只会徒增数据库压力。
很多新手会忽略索引失效场景,我当时也踩过这个小坑。查询条件里用了函数、隐式类型转换,哪怕建了索引,也会变成全表扫描。比如字符串类型的订单编号,查询时传入数字,索引直接失效,排查的时候真的浪费了超多时间。
优化完那次数据库问题后,晚上下班关电脑,盯着后台平稳的监控曲线,没做任何总结,只是默默把所有数据表的冗余索引清单,整理归档存到了项目文档里。