PostgreSQL 16首次为string_agg和array_agg实现完整并行聚合能力,通过新增combine、serial、deserial函数支持partial aggregation,显著提升大数据量下的聚合性能。

string_agg 和 array_agg 现在支持并行聚合
PostgreSQL 16 真正让 string_agg 和 array_agg 跑起来快了——它们首次具备完整的并行聚合能力。这不是简单加个 max_parallel_workers_per_gather 就能生效的“开关”,而是底层实现了 combine、serial、deserial 函数,使这两个聚合能真正参与 partial aggregation 阶段。
常见错误是以为只要开了并行就自动加速。实际中,如果查询里没触发并行执行计划(比如数据量太小、work_mem 不足、或存在不支持并行的子句),string_agg 仍走串行路径。
- 必须确保查询本身被规划为并行(用
EXPLAIN ANALYZE看到Gather或Gather Merge节点) -
string_agg的 delimiter 参数不能是 NULL(否则会退化为串行) - 输入列若含大量 NULL 值,
string_agg默认跳过,但array_agg会保留,影响分片后合并逻辑,建议显式写array_agg(col ORDER BY ...)控制确定性 - 并行下内存使用更分散,需检查
work_mem是否足够支撑多个 worker 同时做局部聚合
SELECT DISTINCT 查询默认走增量排序
如果你的聚合前需要去重(比如 SELECT COUNT(DISTINCT user_id) 或 GROUP BY 前先 DISTINCT),PostgreSQL 16 会尝试用增量排序替代全量排序——前提是 leading 列有可用索引。
典型坑是:明明建了 INDEX ON events(user_id, event_time),但写成 SELECT DISTINCT event_time, user_id FROM events,优化器就无法利用 Presorted Key: user_id,仍回退到 HashAggregate。
- 保持
SELECT DISTINCT的列顺序与索引定义顺序一致(如索引是(a,b),就写SELECT DISTINCT a, b) - 避免在
DISTINCT列上套函数(如SELECT DISTINCT lower(name)),索引失效 - 增量排序对内存极其友好,
Peak Memory可能只有旧版的 1/100,但仅适用于ORDER BY或DISTINCT场景,不适用于普通GROUP BY
别忽略并行聚合的隐式代价
并行不是银弹。string_agg 并行后快了,但可能引发新问题:结果顺序不确定、内存峰值翻倍、甚至因 worker 数量波动导致执行时间抖动。
PostgreSQL 18.4 官方 Ubuntu 安装包现已发布,这是目前最新的稳定版本。推荐通过官方 APT 仓库安装:先执行 sudo apt update 更新索引,再运行 sudo apt install postgresql-18 即可完成部署。新版本引入了异步 I/O 子系统,在顺序扫描与 VACUUM 场景下性能提升显著,同时支持 UUID v7 原生生成函数与虚拟生成列。
最常被忽略的一点:PostgreSQL 16 的并行聚合要求所有 worker 对同一组 key 的局部聚合结果可安全合并。这意味着,如果聚合表达式含 volatile 函数(如 now()、random()),整个并行计划会被禁用。
- 检查执行计划是否真走了并行:找
Partial Aggregate节点,而不是只有Aggregate - 用
EXPLAIN (ANALYZE, BUFFERS)观察各 worker 的Actual Total Time是否均衡;严重不均说明数据倾斜 - 临时关闭并行验证收益:
SET max_parallel_workers_per_gather = 0;对比耗时,尤其在 OLTP 类短查询中,并行开销可能反超收益
物化视图 + 自动刷新仍是高吞吐聚合的首选
即便有了并行聚合,对实时性要求不高的报表类聚合(如日活统计、用户地域分布),物化视图仍比每次跑 string_agg 或 array_agg 更稳。
PostgreSQL 16 没改物化视图语法,但配合逻辑复制增强,现在可以在主库建物化视图,通过逻辑订阅同步到只读报表节点——避免报表查询拖慢交易链路。
- 物化视图定义里尽量用确定性函数,避免
CURRENT_DATE这类导致刷新失败 - 刷新时加
CONCURRENTLY选项(需唯一索引),否则锁表 - 不要依赖物化视图自动刷新机制;生产环境建议用
pg_cron或外部调度器控制刷新时机和资源配额
复杂点在于:并行聚合的收益高度依赖数据分布、内存配置和查询结构。一个 string_agg 在 100 万行上快 3 倍,在 10 万行上可能慢 20%,务必实测。










