EXPLAIN 是 MySQL 查看 SELECT 等语句执行计划的命令,不真正执行而模拟优化器决策;核心字段包括 type(访问类型)、key(实际索引)、rows(预估扫描行数)、Extra(警告信息)、id 与 select_type(执行顺序),需结合多表关联整体分析性能瓶颈。

EXPLAIN 是 MySQL 用来“看透”一条 SELECT(以及 5.6.3+ 版本也支持 UPDATE/DELETE/INSERT)语句怎么执行的命令。它不真正运行 SQL,而是让优化器模拟执行、输出执行计划——相当于给你一张查询的“施工图纸”,告诉你 MySQL 打算怎么查、走哪条路、用不用索引、扫多少行。
怎么看懂 EXPLAIN 输出的核心字段
别被一堆列吓住,日常调优盯紧这 5 个就够了:
-
type:访问类型,性能排序是const>eq_ref>ref>range>index>ALL;看到ALL基本等于全表扫描,得立刻查索引是否缺失或失效 -
key:实际用到的索引名;如果是NULL,说明没走索引(哪怕possible_keys里有候选) -
rows:优化器预估要扫描的行数;这个值不是精确统计,但数量级突增(比如从百变万)往往意味着执行路径劣化 -
Extra:关键警告区;出现Using filesort或Using temporary就代表排序/分组没走索引,大概率要优化 -
id和select_type:多表/子查询时判断执行顺序;id越大越先执行,select_type = DERIVED表示 from 里有子查询且已物化为临时表(注意:该子查询会被真实执行)
为什么加了索引,EXPLAIN 还显示 type=ALL?
常见原因不是索引没建,而是“用不上”:
- 查询条件没覆盖索引最左前缀,比如对联合索引
KEY idx_film_actor_id (film_id, actor_id),只查WHERE actor_id = 1就无法命中 - 对索引字段做了函数操作或隐式类型转换,如
WHERE DATE(create_time) = '2025-12-01'或WHERE user_id = '123'(字段是INT) - 使用了
!=、NOT IN、LIKE '%abc'等无法走索引范围扫描的操作 - MySQL 认为走索引比全表扫描还慢(比如表很小,或索引选择性极差),优化器主动放弃——这时
key为NULL但possible_keys非空
EXPLAIN 的几个实用变种和注意事项
基础 EXPLAIN 只是起点,进阶分析需要这些:
-
EXPLAIN EXTENDED+SHOW WARNINGS:能看到优化器重写后的 SQL,比如把IN子查询转成JOIN,或常量折叠结果 -
EXPLAIN PARTITIONS:仅对分区表有效,会显示实际参与查询的是哪些分区,避免“扫全分区”陷阱 - 执行计划依赖当前数据分布:
rows和key选择受ANALYZE TABLE统计信息影响;表数据大幅变更后记得更新统计信息 - 不同 MySQL 版本优化策略差异大:MySQL 5.7 和 8.0 对
ORDER BY+LIMIT的处理逻辑就不同,不能直接套用旧经验
真正难的不是看懂单行 EXPLAIN,而是把多表 JOIN 的 id 顺序、type 组合、rows 累积效应串起来——比如 rows=100 的表驱动 rows=10000 的表,实际可能扫描百万行。这时候光看单表 rows 没用,得结合连接方式和过滤条件整体估算。


















