EXPLAIN 是查看 MySQL 索引使用情况最直接的方法,需关注 key(非 NULL 表示用索引)、type(const/ref/range 为走索引,ALL 为全表扫描)、rows(远小于总行数说明过滤有效)、Extra(出现 Using filesort 或 temporary 表示额外开销)。

用 EXPLAIN 看执行计划是最直接的方法
MySQL 不会主动告诉你“用了哪个索引”,但 EXPLAIN 会把优化器的决策摊开给你看。在 SQL 前加 EXPLAIN,重点关注 type、key、rows、Extra 这几列:
-
key列非NULL(比如显示idx_user_id)→ 实际使用了该索引 -
type是const/ref/range→ 通常走索引;如果是ALL→ 全表扫描,没走索引 -
rows值远小于表总行数 → 说明索引过滤有效;接近总数则可能失效 -
Extra出现Using filesort或Using temporary→ 即使走了索引,排序/分组仍可能回表或额外开销
注意:仅 key 非空不等于“高效”,还要结合 type 和 rows 综合判断。
哪些写法会让索引“悄悄失效”
索引存在 ≠ 被使用。常见隐形失效场景包括:
- 对索引字段做函数操作:
WHERE YEAR(create_time) = 2023→create_time上的索引失效 -
隐式类型转换:
WHERE user_id = '123'(user_id是INT)→ 可能放弃索引 - 使用
!=或NOT IN(尤其右侧含 NULL)→ 优化器常弃用索引 -
LIKE以通配符开头:LIKE '%abc'→ 无法利用 B+ 树前缀匹配特性 - 联合索引未按最左前缀使用:
INDEX (a, b, c),只查WHERE b = 1→ 不走索引
这些不是语法错误,SQL 能正常执行,但执行计划里 key 会是 NULL,type 变成 ALL。
FORCE INDEX 能强制走索引,但要小心
当优化器误判(比如统计信息过期、小表误选全表扫描),可用 FORCE INDEX 干预:
SELECT * FROM orders FORCE INDEX (idx_status_created) WHERE status = 'paid' AND created_at > '2024-01-01';
但它不解决根本问题:
- 如果索引本身设计不合理(比如缺失覆盖字段),强制后反而更慢
- 后续数据分布变化后,
FORCE INDEX可能从“救急”变“拖累” - MySQL 8.0+ 中,
USE INDEX更温和,IGNORE INDEX有时比硬刚更有用
上线前务必用真实数据量 + EXPLAIN FORMAT=JSON 验证效果,别只看开发环境。
执行流程中索引在哪一步介入
简化版 MySQL 执行流程:连接 → 解析 → 优化(生成执行计划)→ 执行 → 返回。索引参与的是「优化」和「执行」两步:
- 优化阶段:优化器基于统计信息(
SHOW INDEX FROM tbl+INFORMATION_SCHEMA.STATISTICS)、成本模型,决定是否用索引、用哪个、是否下推条件(ICP) - 执行阶段:存储引擎(如 InnoDB)按执行计划调用索引 B+ 树查找,定位到主键或数据页,再回表(若非覆盖索引)
所以,ANALYZE TABLE 更新统计信息、避免长期不 OPTIMIZE 导致页分裂严重,都是影响“是否走索引”的底层因素——它们不改变 SQL 写法,但会改变优化器的选择。










