EXPLAIN ANALYZE会真实执行SQL并返回actual time、rows、loops等实测数据,而普通EXPLAIN仅输出优化器预估的执行计划;两者核心区别在于是否实际运行查询及是否提供真实性能指标。

EXPLAIN ANALYZE 会真实执行查询,必须加 WHERE 限流或在从库/测试环境运行,否则可能拖垮线上服务。
EXPLAIN ANALYZE 和普通 EXPLAIN 的根本区别
普通 EXPLAIN 只让优化器“纸上谈兵”,输出的是预估计划;EXPLAIN ANALYZE 则会真正跑一遍 SQL,记录每个节点的:actual time(毫秒级耗时)、rows(实际返回行数)、loops(循环次数)、内存使用等。两者差距常达数量级——比如一个子查询预估 2 行,实际扫描了 12 万行,这种偏差只有 EXPLAIN ANALYZE 能暴露。
常见错误现象:在生产环境直接对大表执行 EXPLAIN ANALYZE SELECT * FROM orders,导致连接堆积、CPU 拉满。
- 必须提前加过滤条件,例如
WHERE created_at > '2026-10-01' - 禁止在主库高负载时段运行
- 优先用
FORMAT=TREE(默认),结构清晰;需要程序解析时才用FORMAT=JSON
怎么看懂 actual time 和 rows 的偏差
输出中每行末尾类似 (actual time=0.025..0.030 rows=2 loops=1) 是关键。其中 actual time 是该节点自身耗时(不含子节点),rows 是它输出的行数,loops 表示被父节点调用多少次。
典型问题场景:
-
rows=10000但loops=50→ 实际执行了 50 万行扫描,大概率是嵌套循环连接失控 -
actual time明显大于cost→ 磁盘 IO 或锁等待严重,需查performance_schema.data_locks -
rows远大于filtered× 预估rows→ 统计信息过期,应执行ANALYZE TABLE orders
树状结构下如何定位最慢节点
EXPLAIN FORMAT=TREE ANALYZE ... 输出是缩进层级结构,最深的叶子节点最先执行,顶层节点最后完成。瓶颈往往藏在「看似简单但 loops 很高」的位置。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
例如这个片段:
-> Nested loop inner join (cost=120.50 rows=1)
-> Index lookup on e using idx_hire_date (actual time=0.012..0.015 rows=8200 loops=1)
-> Filter: (e.hire_date > DATE'1990-01-01') (actual time=0.008..0.010 rows=7900 loops=1)
-> Index lookup on de using PRIMARY (emp_no=e.emp_no) (actual time=0.021..0.024 rows=1 loops=7900)
最后一行 loops=7900 暴露了问题:对 de 表做了 7900 次主键查找,这是典型的驱动表选错。应该让 de 做驱动表,或给 de(emp_no) 加索引。
- 逐行看
loops值,找异常高的节点 - 对比同级节点的
actual time,时间长 + loops 高 = 重点优化对象 - 若某
Filter节点rows极低但上层Index lookup的rows很高,说明索引没覆盖查询条件
容易被忽略的权限与版本陷阱
EXPLAIN ANALYZE 要求用户有 PROCESS 权限(查看执行细节)和目标表的 SELECT 权限。MySQL 8.0.16+ 才支持 FORMAT=TREE,低于该版本只能用 FORMAT=JSON 或传统表格格式。
性能影响方面:EXPLAIN ANALYZE 会触发真实读取,可能造成 Buffer Pool 污染、临时表创建、甚至锁升级。如果查询本身带 FOR UPDATE 或涉及事务隔离级别敏感操作,结果不可复现。
- 检查版本:运行
SELECT VERSION(),确认 ≥ 8.0.16 - 验证权限:
SHOW GRANTS中必须含PROCESS - 避免在
READ COMMITTED以上隔离级别下分析写操作,否则可能阻塞其他事务
真正难的不是看懂输出,而是把 loops=12000 和业务逻辑里那个被遗忘的 JOIN 条件对应起来——这需要你同时打开 SQL 和表结构,在树状路径里逆向追踪数据流向。










