postgresql 14+中仅语义上可分片聚合再合并的窗口函数才能真正并行,如count(*) over (partition by ...)和avg(...) over (partition by ...);而依赖全局排序或物理顺序的(如row_number()、lag())不可并行,且需同时满足max_parallel_workers_per_gather≥4、parallel_setup_cost与parallel_tuple_cost调低、enable_parallel_tuplestore=on三个硬开关。

窗口函数在大规模数据上默认单线程执行,WindowAgg节点不启动 worker 就代表并行被锁死了——这不是配置没开,而是语义或版本不支持。
哪些窗口函数能真正走并行?看语义,不是看写法
能否并行,只取决于“是否可分片聚合再合并”。有 ORDER BY 的绝大多数不行,无序聚合类才可能生效:
-
COUNT(*) OVER (PARTITION BY user_id)→ 可并行:各 worker 算局部 count,最后 sum -
AVG(sales) OVER (PARTITION BY region)→ 可并行:分别算SUM(sales)和COUNT(*),merge 后除 -
ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary)→ 不可并行:序号依赖全局排序结果,无法拆 -
LAG(sales) OVER (PARTITION BY store ORDER BY day)→ 不可并行:必须按物理顺序读前一行,分片后位置关系丢失
PostgreSQL 14+ 并行窗口的三个硬开关
即使函数语义允许,并行也不会自动开启。这三个配置必须手动调:
-
max_parallel_workers_per_gather:至少设为 4(默认是 2),否则 worker 数被卡死 -
parallel_setup_cost和parallel_tuple_cost:建议调低至0.005和0.001,否则优化器宁可单线程扫完也不拆 -
enable_parallel_tuplestore(PG 14+):必须ON,否则带ORDER BY的窗口即使能并行也 fallback 到单线程
最容易被忽略的一点:并行窗口对数据倾斜极度敏感
如果某个 PARTITION BY 值占全量 80%,那哪怕开了 8 个 worker,实际负载几乎全压在 1 个上——此时索引、分区裁剪或预聚合比调并行参数更管用。










