
SQL 聚合查询慢,核心问题往往不在函数本身,而在数据访问路径、中间结果集大小和统计信息准确性。优化重点是减少扫描行数、避免隐式转换、合理使用索引,并控制 GROUP BY 的基数。
精准定位性能瓶颈
别猜,先看执行计划。重点关注:
- 实际扫描行数 vs 预估行数:偏差大说明统计信息过期,需 ANALYZE 表(PostgreSQL)或 UPDATE STATISTICS(SQL Server)
- 是否出现临时表(Temporary Table)或磁盘排序(Disk Sort):意味着内存不足或 GROUP BY 字段无索引,导致落盘处理
- 聚合前是否有高成本 Filter 或 Join:优先优化前置条件,比如把 WHERE 条件下推,过滤掉 90% 数据后再聚合
索引策略要匹配聚合模式
普通单列索引对 COUNT(*) 或 MIN/MAX 有帮助,但对 GROUP BY + 聚合函数效果有限。应构建覆盖型复合索引:
- 顺序为:WHERE 条件字段 → GROUP BY 字段 → SELECT 中的聚合字段(如需要)
- 例如:SELECT dept_id, COUNT(*) FROM emp WHERE status = 'active' GROUP BY dept_id;可建索引 (status, dept_id)
- 若还需 AVG(salary),且不想回表,可扩展为 (status, dept_id, salary) —— 注意索引宽度与维护成本平衡
控制中间结果集规模
GROUP BY 基数(分组数量)过高会显著拖慢聚合速度。可通过以下方式干预:
- 用 WHERE 提前过滤低频/无效分组值,比如排除 NULL 或测试数据
- 对字符串分组字段考虑前缀索引或规范化(如地区编码替代长地址文本)
- 必要时拆分聚合:先用子查询或 CTE 按大类汇总,再二次聚合,避免单次超大分组
- 慎用 SELECT DISTINCT + 聚合混写,容易触发重复计算,改用标准 GROUP BY 更可控
善用物化与近似算法
对实时性要求不高的报表类聚合,可降低计算压力:
- 用物化视图(PostgreSQL)或索引视图(SQL Server)预存聚合结果,查询直接读取
- 大数据量去重计数(COUNT(DISTINCT))可用 HyperLogLog 等概率算法(如 PostgreSQL 的 hll 扩展),误差率可控在 1% 内
- 分区表按时间/地域切分后,聚合可并行扫描多个分区,再合并结果,比全表扫描快数倍
不复杂但容易忽略:聚合字段类型要和索引字段严格一致,避免隐式类型转换导致索引失效;小表关联大表聚合时,确保驱动表选择合理,必要时用 STRAIGHT_JOIN 或 /*+ leading() */ 提示优化器。











