真实面经题目 · 原创解析

MySQL 查询为什么可能不走索引?

MySQL 不走索引通常不是“索引失效”这么简单,而是优化器认为使用索引的总代价不划算,或者查询条件的写法让索引无法被有效利用。面试中要从索引可用性、选择性、代价模型、联合索引规则和执行计划验证几层回答。

出现于:字节跳动 · 后端开发

60 秒回答模板

可以从两类原因回答:第一类是索引本身虽然存在,但查询条件无法按索引有序结构定位,比如对索引列做函数、隐式类型转换、前置模糊匹配、违反联合索引最左前缀等;第二类是索引能用,但优化器认为不如全表扫描,例如数据量小、条件选择性差、需要大量回表、统计信息不准。实际排查时我会先看 EXPLAIN,确认 type、key、rows、filtered、Extra,再结合表数据分布和 SQL 写法判断是“不具备索引访问路径”,还是“具备但代价更高”。

考点 索引可用但未必划算
难度 真实面经高频题
回答目标 讲清机制、边界和追问

深入解析

01

优化器按成本选择访问路径

MySQL 是否走索引最终由优化器决定,它会估算使用索引扫描、回表、排序、临时表和全表扫描的成本。如果条件命中大量数据,使用二级索引可能需要频繁回表,随机 I/O 和额外读取反而比顺序扫描更贵。尤其是返回比例很高、字段又不覆盖索引时,优化器可能直接选择全表扫描,这不是索引坏了,而是成本模型认为收益不明显。

02

条件写法破坏索引有序性

B+Tree 索引依赖列值的有序排列来快速定位。如果在索引列上做函数、表达式计算、隐式类型转换,或者使用前置通配的模糊匹配,优化器很难直接利用原始索引顺序。例如把列值转换后再比较,本质上要逐行计算结果,索引中保存的原始值就无法用于快速定位。面试时可以强调:尽量让索引列保持“裸列”参与比较。

03

联合索引受最左前缀约束

联合索引不是多个单列索引的简单叠加,而是按定义顺序组成的复合排序结构。只有查询条件从最左列开始连续匹配时,才能有效利用前缀部分;中间跳过某一列,后面的列通常不能继续用于定位。遇到范围条件后,后续列往往只能参与过滤或排序优化,无法继续缩小索引扫描范围。因此联合索引设计要结合等值条件、范围条件、排序字段和查询频率。

04

选择性差会降低索引价值

索引适合快速过滤少量行,如果某个字段重复值很多,例如状态、性别、布尔标记等,单独建索引未必有明显效果。查询命中比例越高,扫描索引再回表的成本越接近甚至超过全表扫描。更合理的做法通常是把低选择性字段放入联合索引中,与高选择性字段组合使用,或者设计覆盖索引,减少回表成本,而不是简单地为每个条件字段都建单列索引。

05

执行计划和统计信息要一起看

排查不走索引不能只靠猜,需要看执行计划里的 key、possible_keys、rows、filtered、Extra 等信息。possible_keys 有值但 key 为空,说明理论可用但未被选择;key 有值但 rows 很大,可能索引过滤效果差;Extra 出现 Using filesort 或 Using temporary,说明排序或分组没有被很好利用。统计信息陈旧也会导致误判,必要时需要更新统计信息,并结合真实数据分布判断优化器选择是否合理。

易错点

  • 把“不走索引”简单等同于“索引失效”,忽略优化器基于成本主动放弃索引的情况。
  • 认为给所有 where 字段都建单列索引就一定更快,忽略联合索引顺序、选择性和回表成本。
  • 只看 key 是否为空,不结合 rows、filtered、Extra 判断索引使用质量。
  • 在索引列上随意使用函数、表达式或隐式类型转换,却期待普通索引仍然稳定生效。

面试官追问

为什么索引列上使用函数可能不走索引?

因为普通 B+Tree 索引保存的是列的原始值顺序,函数计算后的结果不在这个索引结构中。数据库如果要比较函数结果,往往需要逐行计算,无法直接按原索引定位范围。

为什么条件命中很多数据时反而不走索引?

如果命中大量行,二级索引扫描后还要大量回表,随机读取成本很高。此时顺序扫描整张表可能更简单、更稳定,优化器就可能放弃索引。

联合索引中范围查询后面的列还能用吗?

通常范围列后面的列很难继续用于缩小扫描范围,但可能用于索引条件下推、过滤或覆盖。能否发挥作用要结合具体版本、执行计划和索引顺序判断。

遇到不走索引怎么排查?

先看 EXPLAIN,确认 possible_keys、key、type、rows 和 Extra;再检查 SQL 是否有函数、隐式转换、前置模糊匹配、联合索引顺序不匹配;最后看数据分布、选择性和统计信息是否导致成本估算变化。