基于本文回答
0
评论

PostgreSQL EXPLAIN 和 EXPLAIN ANALYZE 有什么区别?

知识点图片

在 PostgreSQL 中,EXPLAINEXPLAIN ANALYZE 都是用于数据库性能调优的强大工具,但它们之间有一个最核心的区别

  • EXPLAIN 只做预测(不执行 SQL)。
  • EXPLAIN ANALYZE 既做预测,又实际执行(真刀真枪跑一遍)。

以下是详细的区别和对比:

1. EXPLAIN:理论与估算

当你运行 EXPLAIN <查询语句> 时:

  • 不执行查询:PostgreSQL 的查询优化器(Planner)会根据数据库收集到的统计信息(如表大小、索引分布等)生成一个执行计划,但绝不会真正去执行这条 SQL。
  • 输出内容:只显示估算值(Estimated)。包括估算的启动成本(cost)、总成本、返回行数(rows)和单行宽度(width)。
  • 速度:瞬间返回结果,因为它不需要真的去读取大量数据。
  • 安全性:绝对安全。你可以放心地对 UPDATEDELETE 或极其耗时的 SELECT 语句使用 EXPLAIN,它不会修改任何数据,也不会卡死数据库。

2. EXPLAIN ANALYZE:实践与真实数据

当你运行 EXPLAIN ANALYZE <查询语句> 时:

  • 实际执行查询:PostgreSQL不仅会生成执行计划,还会真正把这条 SQL 语句执行一遍
  • 输出内容:在 EXPLAIN 估算值的基础上,增加了真实运行时的统计数据(Actual)。包括实际花费的时间(actual time)、实际返回的行数(actual rows)、循环次数(loops),以及底部的“规划时间(Planning Time)”和“执行时间(Execution Time)”。
  • 速度:取决于 SQL 本身的执行速度。如果一条 SQL 原本要跑 10 分钟,EXPLAIN ANALYZE 也要跑 10 分钟以上(因为还要额外记录性能指标)。
  • 安全性(⚠️高危警告)如果不加处理,它会真实改变数据! 如果你执行 EXPLAIN ANALYZE DELETE FROM users;,表里的数据就真的被删除了。

输出结果对比示例

使用 EXPLAIN:

sql
EXPLAIN SELECT * FROM users WHERE age > 30;

输出:

Seq Scan on users (cost=0.00..18.50 rows=300 width=40)
Filter: (age > 30)

(注意:只有 cost 和 rows 的估算值)

使用 EXPLAIN ANALYZE:

sql
EXPLAIN ANALYZE SELECT * FROM users WHERE age > 30;

输出:

Seq Scan on users (cost=0.00..18.50 rows=300 width=40) (actual time=0.025..0.120 rows=280 loops=1)
Filter: (age > 30)
Rows Removed by Filter: 720
Planning Time: 0.085 ms
Execution Time: 0.150 ms

(注意:括号里多出了 actual time 和真实的 rows,并且底部有精确的毫秒级耗时。这能让你看出优化器估算的 300 行和实际的 280 行是否差距过大。)


总结对比表

特性 EXPLAIN EXPLAIN ANALYZE
是否执行 SQL ❌ 否(只生成计划) ✅ 是(真实执行)
耗时 毫秒级返回 等同于甚至略慢于 SQL 实际执行时间
返回数据类型 仅估算值(Cost, Estimated Rows) 估算值 + 真实值(Actual Time, Actual Rows)
排查“统计信息过期” 无法排查(不知道真实行数) 非常有用(对比估算 rows 和实际 rows 即可发现)
对写操作(DML)的影响 安全(不修改数据) 危险(会真实 INSERT/UPDATE/DELETE 数据)

💡 进阶避坑与最佳实践

  1. 如何安全地 EXPLAIN ANALYZE 更新/删除语句?
    由于 EXPLAIN ANALYZE 会真跑数据,对写操作一定要包裹在事务中并回滚

    sql
    BEGIN;
    EXPLAIN ANALYZE DELETE FROM orders WHERE status = 'expired';
    ROLLBACK;

    这样既能看到真实的执行性能,又不会真的删除数据。

  2. 终极排查利器:BUFFERS
    在实际调优时,光看时间通常不够,还需要看内存/磁盘的命中率。强烈建议日常排查慢查询时使用:

    sql
    EXPLAIN (ANALYZE, BUFFERS) SELECT ...

    这会额外输出 Buffers: shared hit=... read=...,明确告诉你这条 SQL 是从内存里读的数据(hit快),还是从磁盘读的数据(read慢)。

右滑查看面试常问