索引失效常见于函数操作、隐式类型转换、!=/, like '%abc'、联合索引不满足最左前缀或范围查询后列失效;需用explain查看type、key、key_len、rows等字段确认。

索引失效的常见 SQL 写法
不是写了 WHERE 条件就一定能走索引。比如对索引列做函数操作:WHERE YEAR(create_time) = 2023,MySQL 无法使用 create_time 上的索引,因为索引中存的是原始值,不是年份计算结果。类似情况还有 UPPER(name)、CONCAT('a', col) 等。
隐式类型转换也会让索引失效。例如字段是 VARCHAR 类型,但查询写成 WHERE col = 123(传了数字),MySQL 会把每行字符串转成数字比对,跳过索引。正确写法是加引号:WHERE col = '123'。
用 != 或 判断时,除非是覆盖索引且优化器认为高效,否则通常不走索引;LIKE 以通配符开头(如 LIKE '%abc')也无法使用 B+ 树索引的有序特性,只能全表扫描。
联合索引没生效的关键原因
联合索引遵循最左前缀原则。假设建了 (a, b, c) 的联合索引:
- WHERE a = 1 AND b = 2 ✅ 能用上索引
- WHERE b = 2 AND c = 3 ❌ 没有 a,跳过整个索引
- WHERE a = 1 AND c = 3 ⚠️ 只能用到 a,b 和 c 不满足连续最左匹配,c 无法走索引
- WHERE a = 1 AND b > 10 AND c = 3 ⚠️ a 和 b 可用,但 c 在范围查询后失效(B+ 树中范围之后的列无法二分)
注意:如果 b 是等值条件,c 才可能继续生效;一旦中间出现范围(>、、<code>BETWEEN),后续列就“断链”了。
如何确认索引是否真的被用了
别猜,用 EXPLAIN 看执行计划。重点关注这几列:
-
type:最好为
const、ref、range;ALL表示全表扫描,index是全索引扫描,都算失效信号 -
key:显示实际使用的索引名;为
NULL就代表没走索引 - key_len:值越小说明用到的索引列越少;对比联合索引定义长度,可判断用了几列
- rows:预估扫描行数;远大于结果集数量,可能是索引未生效或选择性差
执行 EXPLAIN FORMAT=TREE SELECT ... 还能看到更直观的访问路径树,适合复杂查询分析。
其他容易忽略的失效场景
MySQL 优化器有时会主动放弃索引。比如表很小(几千行),它可能觉得全表扫描比走索引再回表更快;或者索引列重复值太多(如 status 只有 0/1),选择性太低,优化器判定索引效率不如全扫。
OR 条件也需小心:WHERE a = 1 OR b = 2,除非 a 和 b 都有独立索引且满足某些条件,否则大概率走全表扫描。可考虑改写为 UNION 或补全索引。
还有 ORDER BY + LIMIT 组合:如果排序字段不在索引中,或顺序与索引不一致(如索引是 (a, b),却 ORDER BY b),MySQL 可能放弃索引而用 filesort。









