postgresql 15 并行聚合需手动配置三参数(max_worker_processes、max_parallel_workers、max_parallel_workers_per_gather)并验证explain (analyze, verbose)中gather节点、workers launched>0及执行时间优化,否则易oom或连接耗尽。

PostgreSQL 15 的并行聚合查询默认不会自动启用,即使表很大、CPU 多核空闲,Gather 节点也常不出现——这不是 bug,而是优化器基于成本估算的保守选择。必须手动干预参数、验证执行计划、并避开几个关键资源陷阱,否则容易引发连接耗尽或内存爆炸。
怎么确认并行聚合是否真被触发
仅看 EXPLAIN 不够,它只显示预估;必须用 EXPLAIN (ANALYZE, VERBOSE) 实际跑一次,并检查输出中三个硬指标:
-
Gather或Gather Merge节点存在,且其子节点是Parallel Aggregate、Parallel Seq Scan或Parallel Index Scan -
Workers Launched值大于 0(比如Workers Launched: 3) -
Actual Total Time明显低于串行等效查询,且Execution Time中 leader 和 worker 时间分布合理(避免 leader 成为瓶颈)
常见误判:看到 Workers Planned: 2 但 Workers Launched: 0,说明系统因资源不足(如 max_parallel_workers 已满)或锁冲突拒绝启动 worker。
必须调的三个参数及其取值逻辑
PostgreSQL 15 中并行聚合依赖三层资源配额,缺一不可,且顺序不能颠倒:
-
max_worker_processes:整个实例允许的最大后台进程数。Aurora PostgreSQL 默认为 8,建议设为 CPU 核心数 × 2(如 16 核 → 设 32),否则后续参数再大也无效 -
max_parallel_workers:专供并行操作(含并行聚合、并行扫描等)的进程上限。必须 ≤max_worker_processes,生产环境建议设为 CPU 核心数(如 16 核 → 设 16) -
max_parallel_workers_per_gather:单个Gather节点最多能拉起几个 worker。默认为 2,对聚合类查询通常需提高到 4~6;但切勿设 ≥ 8 —— 每个 worker 占用独立work_mem,4 个 worker × 64 MB = 256 MB 内存/查询,极易触发 OOM
修改后必须执行 SELECT pg_reload_conf() 生效,无需重启。
为什么 GROUP BY + ORDER BY 容易失败或变慢
并行聚合在 PostgreSQL 15 中对排序敏感:如果 GROUP BY 列未被索引覆盖,或 ORDER BY 与分组键不一致,优化器大概率放弃并行计划,退回到串行 HashAggregate 或更糟的 Sort + GroupAggregate。
- 确保
GROUP BY字段有联合索引,例如CREATE INDEX idx_orders_status_user ON orders (status, user_id) - 避免在聚合后加
ORDER BY,除非必要;若必须,让ORDER BY字段包含在GROUP BY中,或使用Gather Merge(需底层数据已按该字段物理排序) - 检查
work_mem是否足够:并行聚合中每个 worker 都需要自己的work_mem做哈希表,leader 还要额外一份做最终合并。总内存消耗 ≈ (max_parallel_workers_per_gather+ 1) ×work_mem
一个典型翻车场景:SELECT COUNT(*), AVG(amount) FROM sales GROUP BY region ORDER BY COUNT(*) DESC —— 若 region 无索引,且 sales 表达 50 GB,则即使开了并行,也可能因哈希溢出到磁盘而比串行还慢。
OLTP 场景下并行聚合的风险点
高并发事务型负载中,并行聚合不是“开就完事”,它会直接冲击连接池和锁管理:
- 每个并行 worker 占用一个
max_connections槽位(Aurora 中即一个连接槽),一个查询最多消耗max_parallel_workers_per_gather + 1个连接。若设为 4,单个查询就吃掉 5 个连接;10 个并发查询即可打满 50 连接池 - 并行扫描期间仍受 MVCC 快照约束,worker 之间可能因读取同一数据页产生额外缓冲区竞争,
EXPLAIN (ANALYZE, BUFFERS)中若Shared Hit比例骤降、Shared Read激增,就是信号 - 统计信息过期会导致优化器误判:膨胀率 > 20% 的表,
min_parallel_table_scan_size可能失效,建议在业务低峰期定期执行ANALYZE table_name
真正安全的做法是:只对凌晨报表、离线特征计算等低频、长时、独占资源的查询开启并行;OLTP 接口 SQL 建议显式禁用,用 SET LOCAL max_parallel_workers_per_gather = 0 控制粒度。











