预聚合快是因为提前计算并存储结果,避免实时分组的I/O和CPU开销;GROUP BY慢则因每次需读原始数据、排序、聚合,数据量大时性能断崖下跌。

直接结论:预聚合不是“加个索引就能好”,而是把实时计算的负担提前卸载到写入或调度阶段——查得快的前提,是你已经算好了。
为什么GROUP BY查得慢,预聚合却快?
因为数据库每次执行 GROUP BY 都得从磁盘读原始行、分组、聚合、排序,数据量越大,I/O 和 CPU 开销越不可控。而预聚合表(比如每天凌晨跑一次)只存结果,查时直接 SELECT * FROM agg_daily_sales WHERE dt = '2026-07-20',毫秒级响应。
什么场景必须上预聚合?
满足以下任意一条,就该考虑预聚合:
- 报表查询频率高,但数据更新不频繁(如日/周销售TOP10、月度用户留存率)
-
GROUP BY涉及多表JOIN+ 多字段分组 +ORDER BY+LIMIT,EXPLAIN 显示Using temporary和Using filesort - 原始表超千万行,且
WHERE过滤后仍剩百万级数据再分组 - 业务能容忍T+1延迟(例如财务对账、运营日报)
怎么建预聚合表才不踩坑?
关键不是“建表”,而是“怎么同步”和“怎么用”:
- 聚合粒度必须和报表需求严格对齐:要“按商品+日期统计销量”,就建
(item_id, dt)主键,别多加region或少建dt - 写入必须幂等:用
INSERT OVERWRITE(Hive/Spark)或MERGE INTO(PostgreSQL/SQL Server),避免重复累加 - 不要在预聚合表里留冗余字段:比如只查销量,就只存
item_id,dt,sale_cnt,别带item_name—— 那是关联时的事 - 如果原始数据支持删除或修正(如退款冲正),预聚合逻辑里必须包含反向操作,否则结果会漂移
预聚合和物化视图、汇总表有啥区别?
本质一样,但落地方式不同:
-
MATERIALIZED VIEW(PostgreSQL / Oracle / SQL Server):自动刷新、依赖源表统计信息,适合中低频更新、强一致性要求场景 - 手动汇总表(
agg_*命名):调度灵活(可凌晨跑、可事件触发)、易排查、支持自定义清洗逻辑,但需自己管生命周期 - 分区聚合表(如
agg_sales_by_month PARTITION BY month):结合分区裁剪,查某月数据只扫一个分区,适合时间维度强的报表
别迷信“物化视图一定更好”——它在MySQL里压根没有,ClickHouse靠 MATERIALIZED VIEW 但底层是异步追加,一旦源表出错,视图不会自动回滚。

















