EXPLAIN ANALYZE是唯一能揭示执行计划与实际性能差距的工具,它真实执行查询并返回actual time、actual rows和loops等实测数据,而普通EXPLAIN仅依赖可能过期或失准的统计信息预估,易误导优化判断。

EXPLAIN ANALYZE 不是“更好版的 EXPLAIN”,它是唯一能告诉你“计划和现实差距有多大”的工具——尤其当你发现 EXPLAIN 显示走了索引、rows 预估才 100 行,但查询却跑了 3 秒时,必须用它。
为什么普通 EXPLAIN 会骗你?
MySQL 优化器基于统计信息(如 INFORMATION_SCHEMA.STATISTICS)估算执行成本,但这些统计可能过期、不准确,或根本无法反映数据分布偏斜(比如 status=1 占 95%,status=0 只有 5 条)。结果就是:type 显示 ref,key 显示用了索引,rows 显示预估 200 行,而实际扫描了 80 万行。
常见误导场景包括:
- 字符串字段未加引号导致隐式类型转换,
EXPLAIN仍显示key有值,但EXPLAIN ANALYZE会暴露真实扫描行数暴增 - 复合索引前导列未被 WHERE 使用,
possible_keys有值但key为NULL——EXPLAIN看不出是否“部分命中”,而EXPLAIN ANALYZE的actual rows和loops能揭示嵌套循环中某一层反复回表 - 子查询被物化后膨胀,
EXPLAIN的rows是单次预估,EXPLAIN ANALYZE会显示物化临时表大小和构建耗时
EXPLAIN ANALYZE 必须满足的三个条件
它不是开箱即用的功能,漏掉任一条件都会报错或退化为普通 EXPLAIN:
- MySQL 版本 ≥
8.0.18(低于此版本直接报错ERROR 1064) - 语句必须是
SELECT(不支持INSERT ... SELECT中的子查询部分;UPDATE/DELETE不支持) - 用户需具备
PROCESS权限(否则返回空结果或权限错误,而非执行计划)
验证方式:SELECT VERSION(), @@version_comment; + SHOW GRANTS;
看懂 EXPLAIN ANALYZE 输出的关键字段
它的输出是树状结构(默认格式),每行代表一个执行节点,比传统表格多出三列关键实测数据:
-
actual time:格式为0.050..2.312,表示该节点首次返回行到最后一行耗时(单位 ms),点号分隔“启动时间”和“总耗时” -
actual rows:该节点**真实输出的行数**(不是扫描行数!),若远大于rows,说明过滤效率极低 -
loops:该节点被重复执行次数(例如嵌套循环中驱动表每行触发一次被驱动表扫描),乘积actual rows × loops≈ 实际扫描行数
典型陷阱示例:
-> Nested loop inner join (cost=0.70 rows=1)
-> Index lookup on u using status_idx (status=1) (cost=0.35 rows=1000)
actual time=0.021..0.105 actual rows=1000 loops=1
-> Index lookup on o using user_id_idx (user_id=u.id) (cost=0.35 rows=1)
actual time=0.032..1.892 actual rows=1 loops=1000
这里 loops=1000 暴露了本质:外表 1000 行,内表每次查 1 行,但总共执行了 1000 次索引查找——如果 user_id_idx 缓存未命中,IO 放大效应就出来了。
什么时候必须切回 FORMAT=JSON?
当 EXPLAIN ANALYZE 输出里出现 Using temporary 或 Using filesort,且你想确认临时表是否走磁盘、排序是否用到了索引时,FORMAT=JSON 更可靠:
-
EXPLAIN ANALYZE只告诉你“用了临时表”,但不告诉你大小或存储位置 -
EXPLAIN FORMAT=JSON的"buffer_result": true字段表示使用了内存缓冲;"using_temporary_table": true+"using_filesort": true同时出现,基本可判定排序溢出到磁盘 - 二者结合用法:
EXPLAIN ANALYZE FORMAT=JSON SELECT ...(MySQL 8.0.21+ 支持)能一次性拿到实测数据 + 结构化元信息
真正容易被忽略的是:即使 EXPLAIN ANALYZE 显示某步耗时仅 0.2ms,但如果它被调用上万次(loops 很大),累积开销就不可忽视——别只盯单次 actual time,要算总量。


















