高效解决大表聚合慢的方法是预计算,即建按查询模式设计的汇总表,用异步/批量/定时更新,并注意软删除过滤、分区指定和时区统一。

直接在大表上跑 SUM、COUNT 或 GROUP BY,数据一过千万,响应就从毫秒跳到几秒甚至卡住——这不是 MySQL 不行,是它被逼着每次都要重算。真正高效的解法,是把“查询时计算”变成“写入后或定时预计算”,汇总表就是最可控、最落地的方案。
按真实查询模式设计汇总表结构
别凭感觉建表。先看业务里反复查什么:
- 常查“每天各区域订单总金额+笔数”?那就建
summary_daily_region,字段含stat_date、region_id、total_amount、order_count - 还要支持“每小时用户下单分布”?单独建一张
summary_hourly_user,避免把小时粒度硬塞进日表导致冗余和膨胀 -
stat_date必须是DATE类型,不能是DATETIME;region_id不能是拼接字符串,得是整型或规范编码——原子化才好分组、去重、校验
主键与索引要克制,写入优先
汇总表不是明细表,不需要灵活查询。主键就是统计维度组合,比如 PRIMARY KEY (stat_date, region_id)。这样:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 插入或更新时能用
INSERT ... ON DUPLICATE KEY UPDATE实现幂等,不怕重复触发 - 避免用
UUID或自增id当主键,否则写入会随机落盘,拖慢批量补数 - 不额外建索引。它本身已按主键有序,加索引只增写开销,不提读性能
更新策略必须隔离线上业务
绝不能在用户下单事务里同步更新汇总表。正确路径分三类:
- 异步捕获:用触发器或 binlog 解析(如 Canal),把变更发到消息队列,消费者异步写汇总表
-
批量补数:历史数据用
INSERT INTO summary SELECT ... GROUP BY一次性填充,别用循环逐条 INSERT - 定时聚合:对实时性要求不高的指标(如日报),用定时任务每晚执行聚合写入,SQL 简单稳定
三个易错点必须盯紧
汇总表出问题,往往不是技术没做对,而是语义没对齐:
-
软删除漏过滤:明细表有
is_deleted = 1的记录,但汇总逻辑没加WHERE is_deleted = 0,结果虚高 -
分区失效:汇总表按月分区了,但 INSERT 语句没显式指定
PARTITION(p202608),新数据全进默认分区,查询变全表扫 -
时区错位:应用写入用 UTC 时间,报表前端按东八区解析
stat_date,导致“今日数据”永远差 8 小时——所有时间字段统一存 UTC,并在应用层转换
汇总表不是银弹,但它把不可控的查询延迟,变成了可监控、可补救、可预测的数据管道。只要口径一致、更新可靠、读取直接,千万级聚合就能稳在几十毫秒内返回。










