SQL聚合底层主要有Hash Aggregate和Sort-Aggregate两种策略:前者基于哈希表,适合高基数、无序输入,内存充足时高效但输出无序;后者先排序再扫描,适合低基数、已排序输入或需有序输出,内存可控且结果天然有序。

在SQL数据库中,聚合操作(如 GROUP BY、SUM、COUNT 等)的底层实现通常依赖两种主流策略:基于哈希的聚合(Hash Aggregate)和基于排序的聚合(Sort-Aggregate)。二者核心差异在于数据组织方式与适用场景,直接影响性能、内存消耗和结果有序性。
Hash Aggregate:适合无序分组、高基数场景
哈希聚合通过构建哈希表来归集相同键值的行,对每个键维护一个聚合状态(如累加器、计数器)。它不要求输入有序,可流式处理,适合中间结果无序或无法提前排序的情况。
- 内存友好:若哈希表能完全放入内存,效率极高;但数据量超限时可能触发磁盘哈希(spill to disk),显著拖慢速度
- 不保证输出顺序:结果顺序取决于哈希桶遍历顺序,与原始数据或分组键字典序无关
- 适合高基数分组(如按用户ID聚合百万级用户),因哈希查找为O(1)平均复杂度
- 常见于PostgreSQL(
HashAggregate)、SQL Server(Hash Match Aggregate)、ClickHouse(AggregatingHash)
Sort-Aggregate:适合低基数、需有序输出或已排序输入
排序聚合先按分组键排序,再顺序扫描——相同键必然相邻,只需一次遍历即可完成累加。它天然依赖排序稳定性,也常复用已存在的索引排序或上游排序算子。
- 内存开销更可控:排序阶段可能使用外部归并排序,但聚合阶段仅需O(1)额外空间(只存当前组状态)
- 输出天然有序:结果严格按分组键升序(或指定排序方向)排列,省去后续
ORDER BY - 低基数分组更优:当分组键取值少(如按“省份”聚合全国订单),排序成本低,且缓存局部性好
- 若输入已按分组键排序(如走索引扫描),可跳过排序阶段,直接流式聚合,性能极佳
选择依据:看数据特征与执行上下文
优化器不会凭空决策,而是结合统计信息(如分组键的NDV——唯一值数量)、可用内存、输入是否有序、是否需要输出排序等综合判断。
- NDV高 + 输入乱序 + 内存充足 → 倾向 Hash Aggregate
- NDV低 / 输入已按 GROUP BY 键排序 / 查询含 ORDER BY GROUP BY 键 → 倾向 Sort-Aggregate
- 内存不足时,Hash Aggregate 可能退化为多轮磁盘哈希,而 Sort-Aggregate 的外部排序更稳定,但整体变慢
- 某些引擎(如MySQL 8.0+)默认优先尝试 sort-agg,除非估算哈希更优;而 Presto/Trino 默认启用 hash agg 并自动 fallback
手动干预与调优提示
虽然多数现代数据库自动选择,但在特定场景下可通过Hint或配置引导:
- PostgreSQL:用
SET enable_hashagg = off强制禁用哈希聚合 - SQL Server:查询提示
OPTION (HASH GROUP)或OPTION (ORDER GROUP) - ClickHouse:在
GROUP BY后加WITH TOTALS或调整max_bytes_before_external_group_by控制哈希溢出阈值 - 观察执行计划:认准
HashAggregate、SortAggregate、StreamingAgg(表示输入已排序)等节点名称










