EXPLAIN ANALYZE 是什么
MySQL 8.0.18 起的 EXPLAIN ANALYZE 会真正执行语句,再输出每个节点的估算行数与实际行数、实际耗时。它的价值在于暴露“估算偏差”:优化器以为要读 10 行、实际读了 10 万行时,执行计划的选择就会失准,这也是很多慢查询的真正根因。
基本信息
| 版本要求 | MySQL 8.0.18 及以上 |
|---|---|
| 行为 | 真正执行语句,而不是只看计划 |
| 输出结构 | 树形结构,每个节点给出 actual time、rows、loops |
| 时间指标 | actual time 是首行时间..末行时间 |
| 行数指标 | rows 是每次循环的平均行数 |
| 总工作量 | 约等于 rows 乘以 loops,嵌套循环内层必须乘 loops |
| 偏差信号 | 估算 rows 与实测 rows 差距大,说明统计信息需要更新 |
实测输出示例
实测输出示例
EXPLAIN ANALYZE
SELECT o.id, o.total
FROM orders o
WHERE o.user_id = 100
ORDER BY o.created_at DESC
LIMIT 10;
-- 输出片段:
-- -> Limit: 10 row(s) (actual time=0.35..0.42 rows=10 loops=1)
-- -> Index lookup on o using idx_user_created (user_id=100)
-- (actual time=0.12..0.30 rows=8 loops=1)
-- 读法:内层每次循环约 8 行,外层只取 10 行,说明排序被索引顺序满足输出字段读法
| 字段 | 含义 | 异常信号 |
|---|---|---|
| actual time | 首行到末行的实测耗时 | 与其它节点对比,找耗时占比最高的 |
| rows | 每次循环的平均行数 | 与估算值差很多说明统计信息不准 |
| loops | 该节点执行的循环次数 | 总读取量要乘以 loops 才是真实规模 |
| cost(估算) | 优化器的相对代价估算 | 它是相对值,不等于真实耗时 |
| -> 缩进 | 表示父子节点关系 | 缩进越深越先执行 |
典型使用场景
- 慢查询定位:找出真正耗时的节点,而不是凭感觉猜
- 验证索引效果:确认访问方式是索引查找还是全表扫描
- 排查估算偏差:决定是否要更新统计信息或调整索引
- 上线前压测:在预发环境用真实数据量验证执行计划
- 对比优化前后:同一语句两个版本的实测耗时
- 排查 LIMIT 场景:确认取数是否能提前结束而不是全量排序
actual time 包含子节点的累计时间:父节点慢不一定代表它自己慢。先看叶子节点,再逐层往上看哪一层的增量耗时最高,那才是真正的瓶颈。
ANALYZE 会真正执行语句:重查询请挑低峰,写语句要放进事务并回滚。不同版本对写语句的实测支持范围不同,以所用版本的文档为准。