索引在查询优化器生成执行计划后、存储引擎读取数据前被真正调用。EXPLAIN 的 type、key、rows 反映优化器决策结果;WHERE 中函数、隐式转换、低选择性、OR 一侧失效等均可能导致不走索引;确认是否命中需结合 type(如 ref/range)、key(非 NULL)及 rows 判断;InnoDB 中索引实际是 B+Tree 多层磁盘 I/O 查找过程。

MySQL 查询执行时,索引在哪个阶段被真正用到?
索引不是在 SQL 解析完就立刻生效的,而是在 optimizer(查询优化器)完成执行计划生成后、进入 storage engine 层读取数据前才被实际调用。简单说:解析 SQL → 生成执行计划 → 决定是否用索引 → 执行引擎按计划访问索引或表。
关键点在于:EXPLAIN 输出的 type、key、rows 字段,反映的就是优化器「决定用哪个索引」的结果,而不是执行时临时判断。
为什么 WHERE 条件写了索引字段,却没走索引?
常见原因不是语法写错,而是优化器评估后认为全表扫描更快。典型触发条件包括:
-
WHERE中对索引列用了函数,比如WHERE YEAR(create_time) = 2023→ 索引失效(create_time上有索引也不走) - 隐式类型转换,比如
WHERE user_id = '123'(user_id是INT),MySQL 会转成CAST('123' AS SIGNED),导致无法使用索引 - 索引选择性太低,比如在只有两个值的
status列建了索引,且满足条件的数据占 80%,优化器大概率放弃索引 -
OR连接多个条件时,只要其中一侧无法用索引(如WHERE a = 1 OR b LIKE '%x%'),整个条件可能退化为全表扫描
如何确认某条 SQL 是否命中了索引?
不能只看 EXPLAIN 的 key 是否非 NULL,还要结合 type 和 rows 综合判断:
-
type = ref或range且key显示具体索引名 → 基本确认走了索引 -
type = ALL→ 没走索引(全表扫描) -
rows值远大于实际结果行数 → 可能索引统计信息过期,运行ANALYZE TABLE table_name更新 - 注意
Extra字段:出现Using index表示覆盖索引;出现Using where; Using index是理想状态;出现Using filesort或Using temporary往往意味着排序/分组没走索引
EXPLAIN SELECT id, name FROM users WHERE status = 1 AND created_at > '2024-01-01';
索引真正“工作”的底层动作是什么?
以 InnoDB 的 B+Tree 索引为例,当执行引擎决定使用主键索引时,实际发生的是:
- 从根节点页开始,逐层向下比对查找键值(比如
id = 123) - 最终定位到叶子节点页,该页中存的是完整的行记录(聚簇索引)或主键值(二级索引)
- 如果是二级索引查询非索引字段,还需回表:用查到的主键再去聚簇索引里查一次(即二次 B+Tree 查找)
- 每一页默认 16KB,一次磁盘 I/O 读取一页;B+Tree 高度通常为 3~4 层,所以索引查询一般只需 3~4 次 I/O
这个过程完全由存储引擎完成,SQL 层只负责把执行计划中的“用哪个索引”指令传下去。一旦索引字段参与计算、类型不匹配或统计误判,前面所有优化都白搭。










