首页/数据/SQL 速查/PostgreSQL EXPLAIN 基础与 cost 解读
性能与执行计划72 条

PostgreSQL EXPLAIN 基础与 cost 解读

PG 的 EXPLAIN 输出计划树与启动/总成本估算:cost 是统计模型下的抽象单位,用于比较不同计划而非预测耗时。

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

PostgreSQL EXPLAIN 是什么

PostgreSQL 的 EXPLAIN 输出一棵计划树,每个节点带上启动成本与总成本估算:cost=启动..总。cost 是统计模型算出的抽象单位,与页读取代价参数相关,适合同一实例上的计划横向比较,不能当作毫秒读。缩进层级表示父子关系,下层节点先执行,上层消费下层结果。加上 ANALYZE 会真正执行语句并给出真实行数与耗时,加上 BUFFERS 能看到缓存命中情况,是排查性能问题最有效的组合。

基本信息

基本用法EXPLAIN SELECT …
组合选项EXPLAIN (ANALYZE, BUFFERS, VERBOSE) SELECT …
cost=启动..总启动成本是返回首行前的开销,总成本是全过程估算
rows预估返回行数,不是扫描行数
width预估输出行的平均字节宽度
ACTUAL 行只有加 ANALYZE 才出现,是实际执行数据
适用版本PostgreSQL 9.4 起支持 ANALYZE 与 BUFFERS 选项组合

典型使用场景

  • 验证索引是否被使用:看节点是 Index Scan 还是 Seq Scan
  • 比较两种写法的计划:改写前后各跑一次对照成本
  • 定位估算偏差:ANALYZE 后对比 estimated 与 actual 行数
  • 检查缓存命中:BUFFERS 显示 shared hit 与 read 的比例
  • 确认连接方式:Nested Loop、Hash Join 还是 Merge Join
  • 排查排序开销:计划里是否出现 Sort 节点与磁盘排序

示例

示例
EXPLAIN SELECT * FROM orders WHERE user_id = 100;
-- 输出示例:
-- Index Scan using idx_orders_user on orders  (cost=0.43..16.85 rows=10 width=64)
--   Index Cond: (user_id = 100)

-- 真正执行并给出真实数据与缓存统计
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM orders WHERE user_id = 100;
-- 输出会多出 actual time=0.021..0.045 rows=10 loops=1 与 Buffers: shared hit=4

-- 只估算不执行,适合查看写语句
EXPLAIN UPDATE orders SET status = 'done' WHERE id = 1;

常见计划节点

节点含义关注点
Seq Scan顺序扫描全表小表正常,大表需检查索引
Index Scan走索引并回表回表行数多时可考虑覆盖索引
Index Only Scan仅扫描索引不回表可见性映射维护良好时最优
Bitmap Heap Scan位图定位后再取行范围条件常用
Hash Join哈希连接大表连接常见
Nested Loop嵌套循环被驱动表要有索引
Sort排序节点留意是否落盘
cost 是相对代价,不是耗时;不同实例的参数(如 random_page_cost)不同,跨实例比较绝对值没有意义,只看计划之间的相对变化。
EXPLAIN ANALYZE 会真正执行语句,写语句与重查询要谨慎使用,必要时包在事务里执行后回滚。
估算行数与实际行数差一个数量级时,往往是统计信息过期或数据分布倾斜,先 ANALYZE 该表再看计划是否改善。

排查要点

  • 先看有没有 Seq Scan:大表上出现通常意味着索引缺失或条件不匹配
  • 再看估算与实际的差距:差距大先更新统计信息
  • 看连接方式是否合理:小结果集配 Hash Join 或 Nested Loop 各有适用场景
  • 看 Sort 节点是否落盘:排序量大时会显著拖慢查询
  • 用 BUFFERS 判断是缓存不足还是访问量过大
  • 同一实例内做前后对比,跨实例只比结构性差异

易错点

  • 把 cost 数值当耗时看:它是统计模型给出的相对代价,不等同于毫秒
  • 只做 EXPLAIN 不实测:估算偏差大时要用 EXPLAIN ANALYZE 对照实际 rows 与耗时
  • 对写语句直接跑 EXPLAIN ANALYZE,语句被真实执行
  • 忽略计划树的层级关系,把下层节点的成本误读成整条语句的瓶颈
  • 跨实例比较 cost 绝对值,忽略了随机页代价等参数差异

数据来源与参考

  • PostgreSQL Documentation §14.1 Using EXPLAIN
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌