首页/数据/SQL 速查/EXPLAIN 查看执行计划
性能与执行计划72 条

EXPLAIN 查看执行计划

不真正执行语句就返回优化器选择的访问路径:每张表怎么访问、用哪个索引、预估多少行,是排查慢查询的常用起点。

SQL 速查数据更新于 2026-10-13

EXPLAIN 是什么

EXPLAIN 在不真正执行语句的前提下,返回优化器选择的访问路径:每张表怎么访问、用哪个索引、预估扫描多少行。它是排查慢查询的起点,多数慢 SQL 的问题能直接从输出里看出来。普通 EXPLAIN 只做估算,EXPLAIN ANALYZE 会真正执行语句并给出真实行数与耗时,MySQL 8.0.18 起与 PostgreSQL 都支持。EXPLAIN 也可用于 UPDATE 与 DELETE:只做分析,不修改数据。

基本信息

作用查看优化器为语句选择的执行计划,不执行语句
适用语句SELECT、UPDATE、DELETE,视数据库而定
MySQL 格式EXPLAIN 或 EXPLAIN FORMAT=TREE / JSON
PostgreSQL 格式EXPLAIN 或 EXPLAIN (ANALYZE, BUFFERS, VERBOSE)
关键列type、key、key_len、rows、filtered、Extra
前提统计信息准确,否则估算行数与实际偏差很大

典型使用场景

  • 慢查询定位:先看访问方式,再决定加索引还是改 SQL
  • 上线前评估:变更查询前确认不会出现全表扫描
  • 索引验证:新建索引后确认 key 列真的被选中
  • 连接顺序检查:多表连接时看驱动表是不是小结果集
  • 统计信息核对:rows 与实际差距大时考虑更新统计信息
  • 写语句预检:用 EXPLAIN 看 UPDATE 或 DELETE 会扫多少行

示例

示例
EXPLAIN SELECT o.id, o.total
FROM orders AS o
WHERE o.user_id = 100          # 期望走 user_id 上的索引
ORDER BY o.created_at DESC
LIMIT 10;

-- 也可用于写语句,只分析不执行
EXPLAIN UPDATE orders SET status = 'done' WHERE id = 1;
EXPLAIN DELETE FROM orders WHERE created_at < '2023-01-01';

-- MySQL 8.0:树形与 JSON 格式更易读
EXPLAIN FORMAT=TREE SELECT * FROM orders WHERE user_id = 100;

-- PostgreSQL:附带真实执行数据
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM orders WHERE user_id = 100;

读计划先看什么

看哪一列期望值异常信号
typeconst / eq_ref / ref / rangeALL 或 index 说明扫描范围大
key命中了预期索引NULL 表示没走索引
key_len与联合索引前缀长度相符偏短说明只用到前几列
rows估算扫描行数较小数量级明显偏大说明过滤不足
filtered(MySQL)越接近 100 越好很低说明大量行被丢弃
Extra无告警项Using filesort、Using temporary 值得关注
排查顺序:先 EXPLAIN 看访问方式,再判断该加索引、改 SQL 还是更新统计信息,不要凭感觉加索引。
EXPLAIN ANALYZE 会真正执行语句,对更新与删除类语句要特别小心;分析写语句时优先用普通 EXPLAIN。
在数据量很小的开发库上看计划没有参考价值:优化器在不同数据量级下会给出完全不同的选择,评估要贴近生产数据量。
统计信息不准时计划会跑偏,常见诱因是大量写入后未更新统计信息;MySQL 可执行 ANALYZE TABLE,PostgreSQL 可执行 ANALYZE。

排查路径

  • 先看有没有全表扫描:type 为 ALL 或 index 时,确认是过滤条件缺失还是索引没建
  • 再看索引是否被选中:key 为空要检查条件的写法、类型匹配与是否被函数包裹
  • 看扫描行数与返回行数的比例:比例过大说明过滤发生在读取之后
  • 看排序与临时表:Extra 里的 Using filesort 与 Using temporary 是典型额外开销
  • 改前改后各跑一次计划:加索引或改写法后确认变化符合预期
  • 结合慢日志定位重点:先按耗时与执行次数排序,再逐个看计划
  • 统计信息异常时先更新:MySQL 用 ANALYZE TABLE,PostgreSQL 用 ANALYZE

计划解读误区

  • 估算行数不等于实际行数:rows 是统计模型给的估值,偏差明显时要用 EXPLAIN ANALYZE 实测
  • possible_keys 有值不代表用了索引:只有 key 列才是真正被选中的索引
  • type 为 index 不等于优化到位:它扫描整棵索引树,代价接近全表扫描
  • Extra 出现 Using where 未必是问题,要看它发生在索引层还是回表之后
  • 计划会随数据量变化:上线后数据增长,原本正常的计划可能突然变成全表扫描
  • 同一条 SQL 用不同参数会得到不同计划,评估时要覆盖典型参数而不是只试一个值

易错点

  • 只看 possible_keys 就以为会走索引:真正被选中的是 key 列,possible_keys 只是候选清单
  • 在小表测试库上看计划:数据量级差异会让优化器给出完全不同的选择,要贴近生产数据量评估
  • 把 EXPLAIN ANALYZE 用在 UPDATE 或 DELETE 上,语句被真实执行
  • 忽略 Extra 里的 Using filesort 与 Using temporary,问题被反复复现却找不到原因
  • 长期不更新统计信息,计划始终偏离实际数据分布

数据来源与参考

  • MySQL 8.0 Reference Manual · EXPLAIN Statement
  • MySQL 8.0 Reference Manual · Optimizing Queries with EXPLAIN
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌