MySQL索引失效的四大主因:WHERE中对索引列使用函数或表达式;联合索引未遵循最左前缀原则;LIKE左模糊、OR混合无索引列、IS NOT NULL等破坏有序性操作;字段类型不匹配或数据分布偏斜导致优化器放弃索引。
WHERE 里用了函数或表达式,索引直接不走
MySQL 的索引存的是字段原始值,一旦你在 WHERE 条件里对索引列做计算或调用函数,InnoDB 就没法拿索引树里的值去直接比对了。比如 WHERE YEAR(create_time) = 2023,哪怕 create_time 有索引,也白搭。
- ❌ 错误写法:
WHERE DATE(order_date) = '2024-04-21'、WHERE price * 1.1 > 100、WHERE LEFT(name, 3) = 'Joh' - ✅ 正确改法:把函数“挪”到右边,转成范围查询——
WHERE order_date >= '2024-04-21' AND order_date 、WHERE price > 100 / 1.1 - ⚠️ 注意:
CAST()或隐式转换(比如字符串字段查数字)本质也是函数,同样失效,别以为只是“少个引号”而已
联合索引没按最左前缀用,后边全作废
复合索引 (a, b, c) 是按 B+ 树的层级顺序组织的:先排 a,a 相同再排 b,b 相同再排 c。跳过前面的列,就等于找不到入口,整棵树都用不上。
- ❌ 失效场景:
WHERE b = 2 AND c = 3(没 a)、WHERE a = 1 AND c = 3(跳过 b)、WHERE a > 10 AND b = 5(a 是范围,b 后续失效) - ✅ 解法不是硬凑条件,而是看高频查询反推索引设计:如果常查
city和district,就建(city, district),别为了“覆盖更多”硬塞个(country, city, district)却总只查后两列 - ? 补充:范围查询(
BETWEEN、>、LIKE 'abc%')会让其后的索引列失效,不是“不能建”,是“建了也用不上”
LIKE 左模糊、OR 混合无索引列、IS NOT NULL 都容易踩坑
这些看着像语法糖的操作,底层其实破坏了索引的有序性或可预估性,优化器一算——不如全表扫快。