MySQL索引失效10个场景
引言
很多慢查询并不是“没建索引”,而是“建了没用上”。排查时别先加新索引,先确认现有索引为何失效。
场景1:在索引列上做函数运算
示例:where date(create_time) = '2026-03-05'
函数会破坏有序性,导致无法走范围扫描。改为:
where create_time >= '2026-03-05 00:00:00' and create_time < '2026-03-06 00:00:00'
场景2:隐式类型转换
user_id 是字符串,却用数字比较,MySQL 可能做全表转换。类型统一是前提。
场景3:最左前缀未命中
联合索引 (a,b,c),只查 b,c 往往用不上。条件顺序应从左到右利用索引前缀。
场景4:like '%xxx'
前置通配符会导致无法利用 B+Tree 前缀匹配。可以考虑:
- 改业务搜索规则
- 引入倒排索引(ES)
场景5:or 条件一侧无索引
where a = ? or b = ?,若 b 无索引,优化器常放弃索引方案。
场景6:选择性太差
例如性别、状态位这类低基数字段,单列索引收益有限。可结合高选择性字段做联合索引。
场景7:排序与索引方向不匹配
where a = ? order by b,若索引不是 (a,b),容易出现 filesort。
场景8:回表成本高,优化器放弃
即便可以走索引,但回表太多,优化器可能选全表扫描。可用覆盖索引减少回表。
场景9:统计信息过期
表数据分布变化后,执行计划可能退化。需要定期 ANALYZE TABLE。
场景10:SQL写法导致范围过宽
范围条件放在联合索引中间列,会截断后续列利用。索引设计要匹配高频查询形态。
快速排查流程
EXPLAIN看type/key/rows/extra。- 开启
EXPLAIN ANALYZE看真实执行耗时。 - 检查是否出现
Using filesort、Using temporary。 - 对照慢日志确认是否为高频 SQL。
索引治理建议
- 每张核心表维护“主查询清单”。
- 索引命名体现用途,如
idx_order_user_status。 - 定期清理长期未命中的冗余索引。
- 新增索引必须附带可回滚方案。
总结
索引优化是“查询模式优化”,不是“字段越多索引越好”。先找失效原因,再改 SQL 与索引结构,才能稳定提效。