sql中sum慢的根因是数据量大、扫描广、过滤弱、计算重复;有效解法是分区裁剪+预计算双轨并行,辅以覆盖索引和统计信息维护。

SQL中SUM聚合慢,通常不是因为函数本身,而是数据量大、扫描范围广、缺乏有效过滤或计算重复。单纯加索引对SUM帮助有限,真正有效的解法是“分区裁剪 + 预计算”双轨并行:用分区减少物理扫描量,用预计算避免实时累加。
按业务维度合理分区
分区不是越多越好,关键要匹配SUM的常用过滤条件。例如按天汇总订单金额,就用date字段做RANGE分区;按地区分析销售,就用province做LIST分区。确保WHERE子句能精准命中分区,让优化器跳过无关分区。
- 避免用函数分区(如YEAR(create_time)),会导致无法裁剪
- 单个分区数据量建议控制在100万~500万行,过大失去裁剪意义,过小增加管理开销
- 定期清理历史分区(如DROP PARTITION),比delete更高效
用物化汇总表替代实时SUM
对固定维度(如每日各品类销售额)建立汇总表,写入频次远低于查询频次时,预计算收益极高。可结合定时任务(如每天凌晨)或触发器(新增订单后更新当日汇总)维护。
- 表结构示例:daily_category_sales(date, category_id, total_amount, order_count)
- 查询时直接查汇总表,响应从秒级降至毫秒级
- 注意一致性:若支持修改/删除订单,需同步反向修正汇总值
组合使用:分区表 + 汇总表 + 覆盖索引
三者不是互斥,而是分层协同。原始明细表按时间分区;汇总表按相同周期和维度建模;在汇总表上为高频查询字段建覆盖索引(如(date, category_id) include (total_amount)),彻底避免回表。
- 明细表保留原始粒度,用于灵活分析和审计
- 汇总表服务绝大多数固定报表场景
- 覆盖索引让汇总表查询走索引扫描,不读数据页
注意隐式类型转换与统计信息
即使做了分区和预计算,如果WHERE条件存在隐式转换(如字符串字段传数字参数),或分区表统计信息陈旧,优化器仍可能选错执行计划,导致全分区扫描。
- 检查执行计划中Partitions Read是否等于Partitions Total,相等说明未裁剪
- 定期运行ANALYZE table更新统计信息(尤其新增/删减分区后)
- 用EXPLAIN PARTITIONS确认实际访问了哪些分区