postgresql优化器依据统计信息、内存配置和group by列特征选择hashaggregate或groupaggregate,但估算易失准;索引存在会抬高groupaggregate权重,数据倾斜或列相关性会导致误判;扩展统计(pg14+支持四列以上)和analyze可修正估算偏差。

PostgreSQL 优化器不会“随意”选 HashAggregate 或 GroupAggregate,它严格依据统计信息、内存配置和 GROUP BY 列特征做成本估算——但这个估算很容易失准,尤其当多列存在相关性时。
为什么明明有索引,却还是用 GroupAggregate?
索引存在本身会显著抬高 GroupAggregate 的估算权重:优化器看到 c_city 有索引,就默认“走索引 + 排序”比“全表扫 + 哈希建表”更便宜。这不是 bug,是成本模型的合理推断——前提是数据分布均匀。
- 真实场景中,
c_city可能 90% 是 “Beijing”,剩下 10% 分散在 99 个城市,此时索引扫描实际要跳过大量重复值,I/O 效率远低于预期 -
enable_sort = off不会禁用GroupAggregate,因为它是聚合节点类型,不是独立排序步骤;禁用后优化器仍可能选它,只要它认为“索引扫描输出天然有序”更省 - 删除索引后,优化器被迫放弃“有序输入”假设,转而倾向
HashAggregate——这恰恰暴露了它原本依赖索引做的乐观估算
GROUP BY 列越多,越容易 fallback 到 GroupAggregate
当 GROUP BY id1, id2, id3, id4 时,优化器默认按单列统计(n_distinct)估算组合唯一值数量,结果严重低估(比如每列 100 个值,但实际组合只有 100 种),导致 HashAggregate 的内存预估成本虚高。
统一LLM网关 - 一个API对接70+AI模型,使用单一API密钥即可调用GPT、Claude、Gemini、Qwen、Deepseek、Grok等主流模型。
- 解决方法是创建扩展统计:
CREATE STATISTICS s1 ON id1, id2, id3, id4 FROM t1,再ANALYZE t1 - 扩展统计让优化器知道这四列强相关,组合 distinct 数 ≈ 100 而非 100⁴,从而大幅降低
HashAggregate成本分值 - 注意:PG 14+ 才支持四列以上扩展统计;低于此版本需用采样表或业务逻辑拆解
内存不足时 HashAggregate 会被悄悄降级
work_mem 不只影响排序,也硬性约束 HashAggregate 的哈希表大小。当估算所需内存 > work_mem,优化器会直接排除该路径,即使你开了 enable_hashagg = on。
- 查当前会话
work_mem:SHOW work_mem;临时调高:SET LOCAL work_mem = '64MB' - 但别无脑设大——多个并发查询同时用满
work_mem会导致 OOM;建议按查询并发数反推单次上限 - 真正瓶颈常在磁盘哈希(
HashAggregate显示Batches: N且Memory Usage达上限),这时扩work_mem才有效
如何确认到底用了哪种 Aggregate?
别信 EXPLAIN 的估算,看 EXPLAIN (ANALYZE) 的实际节点名和 Actual 行:
- 出现
HashAggregate节点 +Batches: 1+Memory Usage数值 → 真正走了哈希 - 出现
GroupAggregate节点 + 上游带Sort或Index Scan→ 排序聚合已发生 - 如果
GroupAggregate上游是Seq Scan,说明优化器误判了输入有序性——大概率缺扩展统计或统计过期
最易被忽略的是:扩展统计必须配合 ANALYZE 才生效,且 ANALYZE 默认不收集多列统计,必须显式触发。










