SQL聚合操作执行路径分单阶段与多阶段,取决于数据规模、并行能力、内存限制及优化器决策;单阶段在单节点完成哈希聚合,适用于小数据;多阶段含Partial与Final聚合,用于分布式或大数据场景。

SQL数据库中的聚合操作(如 COUNT、SUM、GROUP BY)执行路径是否走单阶段还是多阶段,主要取决于数据规模、并行能力、内存限制以及查询优化器的决策,而非语法本身。
单阶段聚合执行路径
单阶段聚合指所有分组与计算在同一个执行节点(或单个算子)中完成,通常适用于小数据集或本地执行场景。
- 典型场景:表数据量小(如万级以下)、无分布式环境(如 SQLite、单机 MySQL)、或显式禁用并行(
SET parallel_setup_cost = 999999) - 执行流程:扫描全表 → 建立哈希表(key=分组列,value=聚合值)→ 一次遍历完成累加 → 输出结果
- 优势是延迟低、无网络/序列化开销;但易受内存限制,大数据量下可能触发磁盘哈希(spill),反而变慢
多阶段聚合执行路径
多阶段聚合将聚合拆分为局部聚合(Partial Aggregate)和全局聚合(Final Aggregate)两个及以上阶段,常见于分布式或并行查询引擎(如 PostgreSQL 并行查询、Spark SQL、Presto/Trino、ClickHouse)。
- 第一阶段(Partial):各 worker 独立扫描数据分片,对本地数据做初步聚合(如
COUNT(*) → COUNT(*)_partial) - 第二阶段(Merge/Final):将各 partial 结果按 group key 重新分发(Shuffle),再合并(如
SUM(count_partial)) - 部分引擎支持三阶段(如先 local + shuffle + final),用于高基数
GROUP BY场景,缓解 shuffle 压力
影响执行路径的关键因素
优化器不会随意选择阶段数,而是基于代价模型权衡。以下因素直接影响判断:
- 数据分布与分组基数:低基数(如按“省份”分组)倾向单阶段;高基数(如按“用户ID”分组且亿级)更可能启用多阶段避免内存爆炸
-
并行度配置:PostgreSQL 中
max_parallel_workers_per_gather > 0且表足够大时,GROUP BY可能自动转为 partial + final -
聚合函数性质:可分割聚合(
SUM、COUNT、MAX)天然支持多阶段;不可分割的(如STRING_AGG(DISTINCT ...)或窗口函数嵌套)往往退回到单阶段 -
内存与 work_mem 设置:PostgreSQL 中若
work_mem不足,即使想单阶段也会 fallback 到两阶段磁盘哈希
如何观察实际执行路径
通过执行计划确认是否启用多阶段,重点关注节点名称与重分布操作:
- PostgreSQL:
EXPLAIN (ANALYZE, VERBOSE)中出现Partial Aggregate+Gather+Final Aggregate - ClickHouse:
EXPLAIN PIPELINE显示AggregatingTransform出现在多个 processor 阶段 - Spark SQL:物理计划含
HashAggregate(partial)→Exchange(shuffle)→HashAggregate(final) - 注意
Repartition、Shuffle、Distribution等关键词,它们是多阶段的明确信号










