EXPLAIN仅适用于语义合法的SQL,语法错误类报错无法生成执行计划;应先确保SQL能正常执行,再用EXPLAIN分析性能问题,重点关注全表扫描、嵌套循环放大和索引失效三类信号。
执行报错时 EXPLAIN 看不到执行计划?先确认是否真能用
不是所有报错 sql 都能跑 explain —— 语法错误、解析失败类问题(比如 error: syntax error at or near "from")在优化器介入前就挂了,explain 根本不会执行。只有语义合法但结果异常(如空结果、性能差、逻辑错)的 sql,才适合用 explain 辅助定位。
实操建议:
- 先确保 SQL 能正常执行(哪怕返回空),再加
EXPLAIN前缀 - PostgreSQL 中可加
EXPLAIN (ANALYZE, BUFFERS)获取真实执行耗时与缓存命中情况;MySQL 用EXPLAIN FORMAT=JSON看更细的访问路径 - 如果加了
EXPLAIN后报ERROR: relation "xxx" does not exist,说明表名/别名写错,和执行计划无关,得先修语法
EXPLAIN 输出里哪几行最值得盯
重点不是看整张树,而是快速扫出三类信号:全表扫描、嵌套循环放大、索引失效。这些直接对应常见逻辑错误或性能陷阱。
实操建议:
- 找
Seq Scan(PG)或type: ALL(MySQL)—— 没走索引,检查WHERE条件字段是否有索引、是否用了函数(如WHERE UPPER(name) = 'A')、是否类型隐式转换(WHERE id = '123'但id是int) - 看
Rows Removed by Filter(PG)或filtered:(MySQL)数值是否远大于Rows—— 表示大量数据被 WHERE 筛掉,可能条件写反或漏加索引 - 注意
Nested Loop外层输出Rows=1000、内层Rows=1,但实际执行时内层被调用 1000 次——这就是 N+1 的物理体现,应改用JOIN或子查询重写
为什么 EXPLAIN 显示走了索引,结果却不对
执行计划只反映“怎么查”,不校验“查得对不对”。索引走对了,但 SQL 逻辑写错了(比如 LEFT JOIN 写成 INNER JOIN、聚合后没 GROUP BY、OR 条件引发短路逻辑偏差),EXPLAIN 完全不会报警。
实操建议:
- 把
EXPLAIN和原始 SQL 的SELECT *结果对照着看:先手动挑几条关键记录,看 JOIN 后字段是否为空、COUNT 是否少算、ORDER BY 是否乱序 - 对含子查询或 CTE 的 SQL,分段
EXPLAIN:单独EXPLAIN子查询部分,确认其输出行数和字段是否符合预期 - 警惕
Index Scan using idx_xxx on t1后面跟着Filter: (status = 'active')—— 这表示索引没覆盖status字段,过滤动作发生在索引扫描之后,仍可能扫大量无效行
MySQL 8.0+ 和 PostgreSQL 的 EXPLAIN 关键差异点
同一句 SQL,在两个系统里 EXPLAIN 输出结构、术语、甚至优化行为都不同,直接套用经验容易误判。
实操建议:
- MySQL 不显示实际行数估算来源,
rows列是粗略预估;PostgreSQL 的rows基于统计信息计算,更准但依赖ANALYZE是否及时 - MySQL 无
Buffers信息,查缓存效率得靠SHOW STATUS LIKE 'Innodb_buffer_pool%';PG 可用EXPLAIN (ANALYZE, BUFFERS)直接看到shared hit和read次数 - PG 支持
EXPLAIN (VERBOSE)显示投影字段来源(比如某列来自哪个 JOIN 表),MySQL 需靠FORMAT=JSON并读attached_condition字段
真正卡住的时候,往往不是看不懂 EXPLAIN 输出,而是忘了它根本不管语法对错、也不验证业务逻辑。先让 SQL 跑通,再用 EXPLAIN 看它“干了什么”;结果不对,得回过头一行行比对数据,而不是盯着扫描类型打转。










