该建汇总表需同时满足四个条件:高频访问、聚合开销大、基表更新慢、延迟可接受(t+1或小时级);字段精简只留group by字段、聚合值和口径标识,主键按常用过滤顺序设计;采用离线+准实时双层更新,避免全量重刷;补零逻辑必须显性实现,且通过calc_type保障口径一致。

汇总表该不该建,先看这四个条件
汇总表不是万能解药,建错反而拖慢开发、引发数据不一致。是否该建,直接看业务是否同时满足:高频访问、聚合开销大、基表更新慢、延迟可接受(T+1或小时级)。比如“各城市每小时订单量”被运营看板每分钟刷一次,订单表日增500万行,但城市维度仅300个——这就典型该建;而“某用户最近3笔订单详情”这种低频、强明细、需实时的场景,硬塞进汇总表只会增加维护负担。
字段和主键怎么设计才扛得住查询和重跑
汇总表结构比数据本身更关键。字段必须精简:只保留GROUP BY字段(如city、hour_key)、聚合值(如order_cnt、amount_sum)、口径标识(如calc_type='pay_after_refund')。别存order_id或created_at这类明细字段。主键推荐组合键(city, hour_key, calc_type),顺序按常用过滤方向排——比如查某城市某天所有小时,city放最前才能高效走索引;hour_key放中间支持范围扫描;calc_type放最后便于同一维度多口径共存。这样单次任务失败后,可用INSERT ... ON DUPLICATE KEY UPDATE精准覆盖,不用TRUNCATE再全量重刷。
实时更新不能靠定时 truncate + 全量重算
每小时跑一次TRUNCATE sales_hourly; INSERT INTO sales_hourly SELECT ...在数据量上到千万级时,IO会打满,且窗口期无数据。正确做法分两层:
• T+1离线层:凌晨用Spark或Hive跑全量,校验与上游明细sum差值,超0.1%自动告警
• 准实时层:用Flink CDC监听订单表变更,只更新受影响的行——比如新插入一笔北京订单,就UPDATE sales_hourly SET order_cnt = order_cnt + 1 WHERE city = 'beijing' AND hour_key = '2026072112'。注意WHERE条件必须严格对齐业务逻辑,避免漏更新或多更新。
LEFT JOIN 后数据变少?补零逻辑必须显性写进汇总逻辑
原始报表SQL用LEFT JOIN是因为商品类目表可能缺某天销量记录,但汇总表默认只存“有数据”的行,结果总销售额莫名少了5%~10%。这不是BUG,是设计遗漏。解决方案只有两个:
• 所有数值字段用COALESCE(order_cnt, 0)确保不为NULL
• 或在预计算SQL里显式补全维度组合,例如:SELECT c.category_id, d.date_key, COALESCE(s.cnt, 0) FROM (SELECT DISTINCT category_id FROM categories) c CROSS JOIN (SELECT DISTINCT date_key FROM dim_date WHERE date_key BETWEEN '20260720' AND '20260721') d LEFT JOIN sales_summary_daily s ON c.category_id = s.category_id AND d.date_key = s.date_key。后者更重,但语义绝对清晰。
真正容易被忽略的是口径一致性——calc_type字段看着冗余,但当多个团队共用一张汇总表时,它才是唯一能回答“这个DAU到底是去重登录还是去重设备”的依据。没它,表建得再快,三天后谁都看不懂自己写的SQL在算什么。










