优化器选择哈希聚合而非流聚合,根本原因是输入数据未按GROUP BY列有序,导致流聚合不可用;隐式转换、函数操作或统计信息陈旧等均会破坏排序路径,迫使优化器退至哈希聚合。

优化器不是“选择”Hash Aggregate或Stream Aggregate,而是根据输入数据是否有序、成本估算结果和统计信息质量,自动决定唯一可行或更优的路径——你没法手动指定,只能干预它能判断的条件。
Stream Aggregate要求输入严格按GROUP BY列排序
Stream Aggregate本身不排序,它只消费已排序的数据流。一旦输入行在GROUP BY列上出现乱序(哪怕只有一行),它就完全不可用。
- 常见破坏排序的写法:
GROUP BY UPPER(name)、GROUP BY DATE(created_at)、WHERE user_id = 123(user_id是varchar但条件写成数字,触发隐式转换) - ORDER BY混入非分组列也会断掉流聚合路径,例如
GROUP BY user_id ORDER BY created_at - 即使有
INDEX (a, b),若查询是GROUP BY b, a,索引无法提供所需顺序,仍会退到哈希
Hash Aggregate是兜底方案,但容易内存溢出
只要输入无序,优化器就只能选Hash Aggregate。它不依赖顺序,但需要把所有分组键存进内存哈希表——分组基数一高,立刻撑爆。
统一LLM网关 - 一个API对接70+AI模型,使用单一API密钥即可调用GPT、Claude、Gemini、Qwen、Deepseek、Grok等主流模型。
- 看到
Hash warning: Hash bailout(SQL Server)、Spill Level > 0(PostgreSQL)或Using temporary; Using filesort伴随极高rows_examined(MySQL),基本就是哈希表写满硬盘了 - 分组粒度越细越危险:用完整
datetime分组 vs 截断到DATE(datetime),分组数可能从几千跳到百万级 - TiDB、SQL Server、MySQL 8.0 都用相同逻辑:无序 → 哈希;有序 → 流式(除非成本模型算出来哈希更便宜)
真正要调的不是“怎么选”,而是“为什么没选Stream Aggregate”
当执行计划里明明有索引扫描,却跟着一个Sort算子再接Stream Aggregate,说明优化器宁可多一次排序,也不信当前路径能稳定走流式——这背后往往藏着三个被忽略的硬伤:
-
GROUP BY列上有任何函数或表达式,索引失效 - 统计信息陈旧,优化器误判行数,低估排序开销
- 隐式类型转换藏在WHERE或JOIN条件里,让索引无法用于排序输出
这些点不修,光建索引或调配置没用。查执行计划时重点盯Sort前的输入来源,看它是不是本该走索引扫描却走了聚集索引扫描——那八成是上面某条出了问题。

















