mysql索引什么时候会失效_mysql常见失效场景解析

1次阅读

mysql索引失效的四大主因:WHERE中对索引列使用函数或表达式;联合索引未遵循最左前缀原则;LIKE左模糊、OR混合无索引列、IS NOT NULL等破坏有序性操作;字段类型不匹配或数据分布偏斜导致优化器放弃索引。

mysql索引什么时候会失效_mysql常见失效场景解析

WHERE 里用了函数或表达式,索引直接不走

MySQL 的索引存的是字段原始值,一旦你在 WHERE 条件里对索引列做计算或调用函数,InnoDB 就没法拿索引树里的值去直接比对了。比如 WHERE YEAR(create_time) = 2023,哪怕 create_time 有索引,也白搭。

  • ❌ 错误写法:WHERE date(order_date) = '2024-04-21'WHERE price * 1.1 > 100WHERE 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 后续失效)
  • ✅ 解法不是硬凑条件,而是看高频查询反推索引设计:如果常查 citydistrict,就建 (city, district),别为了“覆盖更多”硬塞个 (country, city, district) 却总只查后两列
  • ? 补充:范围查询(BETWEEN>LIKE 'abc%')会让其后的索引列失效,不是“不能建”,是“建了也用不上”

LIKE 左模糊、OR 混合无索引列、IS NOT NULL 都容易踩坑

这些看着像语法糖的操作,底层其实破坏了索引的有序性或可预估性,优化器一算——不如全表扫快。

  • WHERE name LIKE '%john':B+ 树没法从中间开始找,必须逐行扫
  • WHERE a = 1 OR b = 2:如果只有 a 有索引、b 没索引,MySQL 往往放弃索引合并,直接全表扫描
  • WHERE status IS NOT NULL:B+ 树默认不存 NULL 值,查非空就得挨个判断,除非你显式为该列建索引(且字段本身允许 NULL
  • ✅ 应对:左模糊换全文索引或应用层反向索引;OR 拆成 union ALL 或给所有涉及列补索引;IS NOT NULL 查询频繁就加 NOT NULL 约束,或单独建索引

类型不一致、数据太偏斜,优化器主动弃疗

有时候索引明明存在、写法也没错,但执行计划里 type 还是 ALL——不是 bug,是优化器在“理性放弃”。

  • ❌ 字段是 VARCHAR,却写 WHERE phone = 13800138000:MySQL 自动加 CAST(phone AS UNSIGNED),索引失效
  • ❌ 某个值占全表 95%,比如 status = 'active',优化器发现走索引还要回表 95% 的记录,不如直接扫聚簇索引
  • ✅ 验证手段只有一个:EXPLaiNkey 是否命中、rows 是否合理、Extra 有没有 using filesortUsing temporary
  • ⚠️ 最容易被忽略的一点:统计信息过期。大批量导入后没跑 ANALYZE table,优化器还按旧分布估算,可能误判索引价值
text=ZqhQzanResources