以为索引越多越好
很多人刚接触数据库优化时,觉得给字段加索引就像给房间多装几扇门,进出更方便。于是把所有查询涉及的字段都加上索引,结果发现写入速度越来越慢。其实每加一个索引,数据插入、更新、删除时都要同步维护索引结构,尤其是大表,可能一条INSERT语句卡住半秒,就是因为背后在更新七八个B+树。
比如有个订单表,除了主键还给用户ID、订单状态、创建时间、支付方式全建了单独索引。看起来查哪个都快,但每天几万条新订单进来,写性能直接拖垮。真正该做的是分析高频查询路径,合并成联合索引,减少冗余。
联合索引顺序随便排
有人建联合索引时按字段名拼音排序,或者谁在SELECT里靠前就放前面。这完全忽略了最左匹配原则。比如有索引 (status, created_at, user_id),查询时如果只用到 created_at 和 user_id,这个索引根本不会被命中。
正确的做法是把筛选性高、使用频率高的字段放前面。例如订单状态只有“待付款、已发货、已完成”三种值,区分度低,就不适合放联合索引第一位;而用户ID或创建时间这种范围广的,更适合前置。
对模糊查询加普通索引有效
经常看到这样的SQL:SELECT * FROM users WHERE name LIKE '%小明%',然后抱怨为什么name字段明明有索引却还是慢。问题出在开头用了%。B+树是按前缀排序的,你从中间或结尾开始匹配,等于让图书馆按书名排序却要找标题包含“科技”的书,只能一本本翻。
如果真要支持前后模糊,可以考虑全文索引或ES;如果是前缀固定,比如以“张”开头,那 LIKE '张%' 是能走索引的。
忽视隐式类型转换导致索引失效
有张用户表,手机号字段是VARCHAR,索引也建好了。但下面这条SQL还是全表扫描:
SELECT * FROM users WHERE phone = 13812345678问题在于传的是数字,MySQL会做隐式转换,相当于把每一行的phone转成数字比较,索引自然失效。应该统一类型,传字符串:SELECT * FROM users WHERE phone = '13812345678'认为索引能解决所有查询慢的问题
有些同事一发现页面加载慢,第一反应就是“加个索引试试”。但实际可能是关联查询没走JOIN条件、子查询嵌套太深、返回字段太多导致IO压力大。比如一个列表页查了20个字段,其中还包含TEXT类型的简介,即使索引命中,每行数据体积太大,网络传输和内存占用也会拖慢响应。
这时候应该先看执行计划,用EXPLAIN分析是否真的走了索引,扫描行数多少,有没有Using filesort。有时候少查几个字段,或者拆分大字段到附表,比加索引更管用。
忽略统计信息过期的影响
MySQL的查询优化器依赖统计信息判断走哪个索引。但如果表数据变化剧烈,比如半夜跑批处理插了几百万条记录,统计信息没更新,优化器可能误判,选择了一个本不该走的索引,甚至放弃使用索引。
可以通过 ANALYZE TABLE table_name; 手动刷新统计信息。特别是那些频繁变更的大表,定期执行有助于优化器做出正确决策。