一、预聚合技术概述:什么是预聚合、为什么需要预聚合、预聚合的典型应用场景
大家好,我是老张。做了十几年数据库,我见过太多查询慢到让人崩溃的场景。今天咱们聊聊预聚合——一个能大幅降低查询延迟的利器。
说白了,预聚合就是「提前算好,存起来,查的时候直接拿结果」。你想想看,如果每次查询都要扫描几亿行数据,再实时做 sum、count、avg,那得多慢?预聚合的思路就是:在数据写入的时候,就把这些聚合结果算好,存到另一张表里。查询的时候,直接读这张小表,几毫秒就出结果。
核心思想:用存储空间换查询时间。把计算压力从查询阶段转移到写入阶段。
1.1 为什么需要预聚合?
我刚开始做OLAP系统时,遇到过这么个事。一个电商客户,每天产生几千万条订单数据。运营想看「昨天各品类的销售额排名」,每次查询要跑30秒。老板等不了,运营也等不了。
为什么会这样?因为原始数据太「细」了。每条订单包含用户ID、商品ID、下单时间、支付金额、优惠券信息……几十个字段。但运营只关心「品类+日期+销售额」这三个维度。每次查询都要全表扫描,能不慢吗?
预聚合解决的就是这个矛盾。它把高频查询需要的维度提前组合好,算好结果。查询时直接命中,不用再碰原始数据。
具体来说,预聚合有这几个好处:
- 查询延迟从秒级降到毫秒级——我见过最夸张的案例,从120秒降到20毫秒
- 降低系统负载——不用每次查询都跑MapReduce或Spark任务
- 支持高并发——预聚合表通常很小,可以轻松扛住几百甚至上千的QPS
- 简化查询逻辑——业务方写SQL时,不用再写复杂的group by和聚合函数
我的经验:预聚合不是银弹。它适合「查询模式固定、维度组合有限」的场景。如果查询维度组合太多,预聚合表会爆炸式增长,反而得不偿失。
1.2 预聚合的典型应用场景
预聚合在三个领域用得最多:OLAP分析、实时数仓、监控系统。我分别说说。
1.2.1 OLAP分析场景
OLAP(联机分析处理)是预聚合的「老家」。像Apache Kylin、Druid、ClickHouse这些系统,核心能力就是预聚合。
举个例子。一个广告平台,每天产生10亿条曝光日志。分析师想看「按广告主、按日期、按地域」的曝光量和点击量。如果每次都扫描10亿条数据,再group by三个维度,光shuffle就要几分钟。
预聚合的做法是:在数据导入时,就按(广告主, 日期, 地域)这三个维度组合,算好曝光量和点击量,存到一张小表里。这张小表可能只有几百万行。查询时直接select,秒出结果。
| 维度组合 | 原始数据行数 | 预聚合后行数 | 查询延迟 |
|---|---|---|---|
| 广告主+日期+地域 | 10亿 | 500万 | 200ms |
| 广告主+日期 | 10亿 | 50万 | 50ms |
| 广告主 | 10亿 | 1万 | 10ms |
你看,维度越粗,预聚合后的数据量越小,查询越快。
1.2.2 实时数仓场景
实时数仓对延迟的要求更苛刻。数据进来后,几秒内就要能查到聚合结果。这时候预聚合几乎是唯一的选择。
我记得有个金融客户,要做实时风控。每笔交易进来后,需要实时计算「该用户过去5分钟的交易总额」。如果每次查询都去扫过去5分钟的交易明细,根本来不及。
解决方案是:用Flink或Spark Streaming做流式预聚合。每来一条交易,就更新用户维度的聚合结果。查询时直接读这个实时更新的聚合表,毫秒级返回。
注意:实时预聚合要处理好「迟到数据」的问题。比如交易已经聚合完了,突然来了一条5分钟前的数据。这时候需要做数据修正,否则聚合结果会不准。我踩过这个坑,后面会详细讲。
1.2.3 监控系统场景
监控系统是预聚合的另一个「重灾区」。像Prometheus、InfluxDB、OpenTSDB这些时序数据库,底层都大量使用预聚合。
监控数据的典型特点是:写入量大、查询模式固定。比如每台机器的CPU使用率,每5秒采集一次。一个月下来,一台机器就有50万条数据。如果集群有1000台机器,那就是5亿条。
但监控查询通常只看最近1小时、最近1天、最近1周的趋势。预聚合的做法是:按时间粒度做降采样。比如:
- 原始数据:5秒粒度,保留7天
- 预聚合1:1分钟粒度(取平均值),保留30天
- 预聚合2:1小时粒度(取平均值),保留1年
查询「最近1周的CPU趋势」时,直接读1小时粒度的预聚合表,数据量只有原始数据的1/720。查询速度自然快得多。
1.3 预聚合的核心逻辑
说了这么多,我画张图帮你理清思路。这张图展示了预聚合在数据链路中的位置和作用。
这张图展示了预聚合的完整链路。数据源进来后,分两条路走:一条进预聚合引擎,算出聚合结果存到小表;另一条进原始存储,留着查明细用。查询请求直接打预聚合表,毫秒级返回。原始数据只在需要查明细时才用。
1.4 什么时候该用预聚合?
我总结了几条判断标准,你可以对照着看:
- 查询模式固定——业务方经常查同样的维度组合,比如按天、按品类、按地域
- 数据量大——单表数据量超过千万级,全表扫描太慢
- 对延迟敏感——查询需要在秒级甚至毫秒级返回
- 维度组合可控——预聚合的维度组合不超过几十种,否则存储会爆炸
如果满足以上条件,预聚合就是你的最佳选择。如果不满足,比如查询维度组合有几千种,那预聚合就不太合适。这时候可以考虑其他方案,比如列式存储、物化视图、或者干脆上分布式MPP数据库。
我的建议:刚开始做预聚合时,不要贪多。先选2-3个最常用的维度组合做预聚合,看看效果。效果好再加。我见过太多人一上来就搞几十个预聚合表,结果存储爆了,维护成本也高,最后不得不回退。