postgresql 16并行group by需聚合函数支持partial mode且满足数据量、成本等条件;仅string_agg(无order by)、array_agg、sum/max/min/count(非distinct)等可触发,explain中出现gather+partial aggregate即生效。

PostgreSQL 16 中的并行 GROUP BY 不是自动开启的魔法开关,它依赖聚合函数是否支持 Partial Mode,且只对特定场景生效——比如 string_agg 和 array_agg 这类可拆分聚合;而 COUNT(DISTINCT ...) 或带 ORDER BY 的 string_agg 就不行。
为什么 EXPLAIN 看不到 Gather 节点?
即使开了并行参数,GROUP BY 查询仍可能走串行 GroupAggregate。常见原因有:
- 底层聚合函数不支持并行:例如
count(distinct x)、avg(x)(16 之前)、或带ORDER BY子句的string_agg(x, ',' ORDER BY y),它们无法被拆成 partial + final 阶段 - 表太小:默认
min_parallel_table_scan_size = 8MB,若实际扫描数据量低于该阈值,优化器直接跳过并行路径 - cost 估算压制:
parallel_setup_cost(默认 10)和parallel_tuple_cost(默认 0.1)过高,会让并行计划预估成本高于串行 - 查询含禁止并行的操作:如 volatile 函数、某些窗口函数、或
FOR UPDATE锁
哪些 GROUP BY 场景真能并行?
只有满足「可分片 + 可合并」条件的聚合才可能触发并行。PostgreSQL 16 明确支持并行的典型组合:
-
GROUP BY+string_agg(col, ',')(无ORDER BY) -
GROUP BY+array_agg(col)(无ORDER BY) -
GROUP BY+jsonb_agg(col)、json_agg(col) -
GROUP BY+ 基础标量聚合如sum()、max()、min()、count()(非 distinct)
验证方式很简单:EXPLAIN (ANALYZE, VERBOSE) 输出中出现 Gather 或 Gather Merge 节点,且子节点含 Partial Aggregate,就说明并行已生效。
PostgreSQL 18.4 官方 Ubuntu 安装包现已发布,这是目前最新的稳定版本。推荐通过官方 APT 仓库安装:先执行 sudo apt update 更新索引,再运行 sudo apt install postgresql-18 即可完成部署。新版本引入了异步 I/O 子系统,在顺序扫描与 VACUUM 场景下性能提升显著,同时支持 UUID v7 原生生成函数与虚拟生成列。
怎么调参让并行 GROUP BY 真跑起来?
光靠默认配置,多数中小规模表根本不会触发并行。关键参数要手动干预:
- 设
SET max_parallel_workers_per_gather = 4;(根据 CPU 核心数调整,别超max_worker_processes) - 调低门槛:
SET min_parallel_table_scan_size = 1MB;(测试时可用,生产慎用) - 压低启动成本:
SET parallel_setup_cost = 2;和SET parallel_tuple_cost = 0.01; - 确保
work_mem足够:每个 worker 进程会独立申请work_mem,总内存消耗 = (1 +max_parallel_workers_per_gather) ×work_mem;设太小会退化为磁盘排序
注意:max_parallel_workers_per_gather 是 per-query 限制,不是全局并发上限;它只影响单个 Gather 节点下的 worker 数,不影响多个查询同时运行。
并行 GROUP BY 容易踩的坑
并行不是万能加速器,用错反拖慢:
- 小结果集反而更慢:比如
GROUP BY后只出几十行,但启动 4 个 worker 协调开销可能占到总耗时 30% 以上 - 内存爆掉:
work_mem设为 64MB,开 4 个 worker,单查询就吃掉 320MB 内存,高并发下容易 OOM - 分区表上误判:即使主表大,若查询命中单个分区且该分区很小,仍不会并行——并行决策基于**实际扫描的物理数据量**,不是整个表大小
-
string_agg并行后顺序不保证:并行打散再合并,结果字符串内元素顺序可能和串行不同(除非加ORDER BY,但那样就失去并行资格)
最常被忽略的一点:并行聚合的正确性依赖于函数的数学性质(associative + commutative),PostgreSQL 只对明确标记支持 Partial Mode 的函数启用并行。别指望给自定义聚合函数随便加个 PARRALLEL SAFE 就能并行 GROUP BY——它还得实现 combinefunc 和 serialfunc/deserialfunc 才行。










