group by查得慢是因为每次执行都要全量读取、排序、分组、聚合,i/o和cpu开销随数据量剧增;汇总表查得快因只存预计算结果,查询直接命中索引或分区,毫秒级响应。

为什么GROUP BY查得慢,而汇总表查得快
因为每次执行 GROUP BY 都要从原始表读取全部符合条件的行,再排序、分组、聚合——数据量越大,I/O 和 CPU 开销越不可控。而汇总表(比如 agg_daily_sales)只存计算好的结果,查时直接 SELECT * FROM agg_daily_sales WHERE dt = '2026-07-20',毫秒级响应。
汇总表建表时必须对齐报表需求粒度
建错粒度等于白干:要“按商品+日期统计销量”,主键就得是 (item_id, dt);如果报表还要看渠道,那就要加 channel_id;但别多加 region_name 这种文本字段——它该在查询时关联,不该进汇总表。
- 粒度不匹配会导致 JOIN 多余、WHERE 过滤失效、甚至漏数据
- 时间字段(如
dt)必须保留,否则无法做分区裁剪或 T+1 查询 - 避免冗余字段:只存聚合值(
sale_cnt,total_amount),不存原始明细字段(如order_id,user_name)
写入汇总表必须幂等且支持修正
原始数据若支持退款、删单、冲正,汇总逻辑里就得有反向操作。比如某天销量先算出 1000,后来发现 50 单要撤回,不能简单重跑全量——得用 MERGE INTO 或 INSERT OVERWRITE PARTITION,靠 item_id + dt 去重更新,否则结果会持续漂移。
- MySQL 没有原生
MERGE,得用REPLACE INTO或先DELETE再INSERT - Hive/Spark 推荐
INSERT OVERWRITE TABLE agg_sales PARTITION (dt='2026-07-20') - PostgreSQL 物化视图刷新不自动处理数据修正,得配合
REFRESH MATERIALIZED VIEW CONCURRENTLY+ 手动校验
别混淆汇总表、物化视图和普通视图
它们存储方式和刷新机制完全不同:MATERIALIZED VIEW 是物理存储+自动刷新(但 MySQL 不支持);手动汇总表(agg_* 命名)靠调度任务驱动,灵活可控;普通视图只是 SQL 封装,查一次跑一次原始聚合。
- 物化视图在 ClickHouse 里底层是异步追加,源表出错不会自动回滚
- 分区汇总表(如
agg_sales_by_month PARTITION BY month)能结合分区裁剪,查单月只扫一个分区,比不分区快数倍 - 如果业务能接受 T+1 延迟,手动汇总表比物化视图更易排查、更易加清洗逻辑(比如过滤测试订单)
真实场景里最常被忽略的点是:汇总表不是建完就一劳永逸的,它的生命周期、刷新频率、与原始数据的一致性校验,都得有配套机制。没有这些,它很快就会变成“看起来快、实际上不准”的幻觉。











