技术分享 | PostgreSQL 18 执行计划新特性揭秘
在2025-09-25发布的PostgreSQL新版本PostgreSQL 18 中,对EXPLAIN执行计划进行了多项改进:
官方ReleaseNote 中列出了以下8点:
https://www.postgresql.org/docs/18/release-18.html
EXPLAIN ANALYZE 默认包含 BUFFERS 输出:无需显式指定 BUFFERS 选项,EXPLAIN ANALYZE 现在自动报告缓冲区使用细节(如 shared hit/read 等),便于识别 I/O 性能问题。
增强 WAL 缓冲区报告:EXPLAIN (WAL) 输出现在包含完整的 WAL 缓冲区计数,提升了对写前日志活动的可见性。
索引扫描节点报告索引查找次数:在 EXPLAIN ANALYZE 中,每个索引扫描节点会报告实际执行的索引查找次数,帮助评估索引效率。
分数行数估计:EXPLAIN 输出现在支持分数行数,提供更精确的估计报告,提高计划准确性。
内存和磁盘使用细节:针对 Materialize、Window Aggregate 和 CTE 节点,EXPLAIN 输出新增内存/磁盘使用统计,便于评估资源消耗。
窗口函数参数细节:EXPLAIN 输出现在包含窗口函数参数的详细信息,便于理解窗口操作。
并行位图堆扫描统计:EXPLAIN ANALYZE 报告 Parallel Bitmap Heap Scan 节点的 worker 缓存统计,提升并行查询分析。
禁用节点指示:EXPLAIN ANALYZE 输出会标记已禁用的节点,便于识别计划中的非活跃元素。
其中社区反馈比较有用的有 EXPLAIN ANALYZE 默认包含 BUFFERS 输出、索引扫描节点报告索引查找次数等,接下来举例(基于官方测试库https://github.com/postgres/postgres/tree/REL_18_0/src/test/regress)介绍下这两个特性。
EXPLAIN ANALYZE 现在新增了缓冲区结果(shared hit/read 等),无需显式指定 BUFFERS 选项。这帮助快速识别 I/O 瓶颈,例如缓存命中率高低。
SQL样例
EXPLAIN ANALYZE SELECT *FROM tenk1 t1, tenk2 t2WHERE t1.unique1 < 10 AND t1.unique2 = t2.unique2;
执行计划样例
QUERY PLAN--------------------------------------------------------------------------------------------------------------------------------- Nested Loop (cost=4.65..118.50 rows=10 width=488) (actual time=0.017..0.051 rows=10.00 loops=1) Buffers: shared hit=36 read=6 -> Bitmap Heap Scan on tenk1 t1 (cost=4.36..39.38 rows=10 width=244) (actual time=0.009..0.017 rows=10.00 loops=1) Recheck Cond: (unique1 < 10) Heap Blocks: exact=10 Buffers: shared hit=3 read=5 written=4 -> Bitmap Index Scan on tenk1_unique1 (cost=0.00..4.36 rows=10 width=0) (actual time=0.004..0.004 rows=10.00 loops=1) Index Cond: (unique1 < 10) Index Searches: 1 Buffers: shared hit=2 -> Index Scan using tenk2_unique2 on tenk2 t2 (cost=0.29..7.90 rows=1 width=244) (actual time=0.003..0.003 rows=1.00 loops=10) Index Cond: (unique2 = t1.unique2) Index Searches: 10 Buffers: shared hit=24 read=6 Planning: Buffers: shared hit=15 dirtied=9 Planning Time: 0.485 ms Execution Time: 0.073 ms
注意每个节点的 Buffers 行(如 shared hit=36 read=6)
shared:共享缓冲区(Shared Buffers),PostgreSQL 的全局内存池,用于缓存数据页。查询默认从这里读取。
hit=36:缓存命中次数。表示从共享缓冲区内存中直接获取了 36 个数据页(8KB/页),无需访问磁盘。
read=6:读取次数。从磁盘(或 OS 缓存)读取了 6 个数据页到共享缓冲区。这涉及实际 I/O 操作,开销较高。
命中多于读取是比较理想的情况。
▍索引扫描节点报告索引查找次数 索引优化是日常痛点,此特性量化查找次数,帮助评估 IN 子句或多值查询效率。
SQL样例
EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE thousand IN (1, 500, 700, 999);
执行计划样例
QUERY PLAN---------------------------------------------------------------------------------------------------------------------------------- Bitmap Heap Scan on tenk1 (cost=9.45..73.44 rows=40 width=244) (actual time=0.012..0.028 rows=40.00 loops=1) Recheck Cond: (thousand = ANY ('{1,500,700,999}'::integer[])) Heap Blocks: exact=39 Buffers: shared hit=47 -> Bitmap Index Scan on tenk1_thous_tenthous (cost=0.00..9.44 rows=40 width=0) (actual time=0.009..0.009 rows=40.00 loops=1) Index Cond: (thousand = ANY ('{1,500,700,999}'::integer[])) Index Searches: 4 Buffers: shared hit=8 Planning Time: 0.029 ms Execution Time: 0.034 ms
Index Searches: 4 表示查询的 4 个不连续值各触发一次索引查找(非相邻叶页)。如果值相邻(如 IN (1,2,3,4)),则可能降为 1 次,时间更短:
EXPLAIN ANALYZE SELECT * FROM tenk1 WHERE thousand IN (1, 2, 3, 4); QUERY PLAN---------------------------------------------------------------------------------------------------------------------------------- Bitmap Heap Scan on tenk1 (cost=9.45..73.44 rows=40 width=244) (actual time=0.009..0.019 rows=40.00 loops=1) Recheck Cond: (thousand = ANY ('{1,2,3,4}'::integer[])) Heap Blocks: exact=38 Buffers: shared hit=40 -> Bitmap Index Scan on tenk1_thous_tenthous (cost=0.00..9.44 rows=40 width=0) (actual time=0.005..0.005 rows=40.00 loops=1) Index Cond: (thousand = ANY ('{1,2,3,4}'::integer[])) Index Searches: 1 Buffers: shared hit=2 Planning Time: 0.029 ms Execution Time: 0.026 ms
有助于优化 WHERE IN (多值) 查询,识别不连续键的额外开销。


1️⃣ 免费下载/在线试用
官网 https://www.dbdoctor.cn/?utm=01
2️⃣ 产品文档https://demo.dbdoctor.cn/modules/dbDoctor/mdPreview/index.html?readme=help#/