4. 事实表设计:三种快照模型的应用场景

事实表设计,说白了就是回答一个问题:你要度量什么? 度量粒度怎么切,直接决定了查询能不能跑得动。我见过太多团队一上来就建一张超级大宽表,结果跑个月度汇总要半小时——这就是事实表类型选错了。

事实表有三种经典类型:事务事实表、周期快照事实表、累积快照事实表。它们不是互斥的,实际项目中经常混着用。嗯,我们先搞清楚各自长什么样。

4.1 事务事实表:记录每一次发生

事务事实表,就是每发生一笔业务,就记一行。比如电商订单,用户下一单,订单表里就多一条记录。这是最基础、最常用的事实表类型。

核心特征: 一行代表一个业务事件,粒度最细,数据量最大。

我在项目中遇到过这样一个场景:某电商平台要分析用户下单行为,每天几百万笔订单。如果用事务事实表,直接按订单ID做主键,每笔订单一行。查询「昨天每个品类的销售额」时,直接 sum 金额字段,按品类分组就行——快得很。

适用场景:

  • 需要分析单个事件细节(如每笔订单的金额、时间)
  • 需要做事件计数(如每天下单次数)
  • 维度变化不频繁,或者变化时用退化维度处理

避坑指南: 我曾经犯过一个错——把事务事实表当成万能表。有个金融项目,客户要查「每个账户截至昨天的累计余额」,我直接用事务事实表去 sum 所有交易流水。结果呢?每天跑一次全量扫描,几十亿行数据,跑一次要两小时。后来改成周期快照,问题才解决。

注意: 事务事实表不适合做「截至某个时间点的状态查询」。比如查「当前库存量」「当前账户余额」,用事务事实表去累加历史数据,性能会非常差。

4.2 周期快照事实表:定期拍一张照片

周期快照,就是每隔固定时间(比如每天、每小时)把业务状态「拍一张照」。每一行代表某个对象在某个时间点的快照。数据量比事务事实表小得多,因为它是按周期聚合的。

你想想看,银行每天都要算每个账户的日终余额。如果用事务事实表,得把当天所有交易流水累加一遍。但用周期快照,每天只存一行:账户ID、日期、日终余额。查询「上个月每个账户的平均余额」时,直接 sum 日终余额再除以天数,几秒钟就出结果。

适用场景:

  • 需要分析某个时间点的状态(如库存量、账户余额)
  • 需要做周期性汇总(如月度销售目标完成率)
  • 事务数据量太大,但业务只需要周期汇总结果
对比维度 事务事实表 周期快照事实表
粒度 每笔事件一行 每个周期每个对象一行
数据量 大(随事件数增长) 小(随周期数增长)
典型查询 某段时间内的事件统计 某个时间点的状态或周期内累计
更新方式 只追加,不更新 覆盖或追加(取决于设计)

我个人习惯,在数据量超过 10 亿行的事务表上,如果业务只需要日报、月报,优先考虑周期快照。能省掉 90% 的存储和查询时间。

4.3 累积快照事实表:跟踪一个流程的完整生命周期

累积快照,专门用来跟踪一个业务流程从开始到结束的完整状态。每一行代表一个业务实例(比如一个订单、一个工单),但这一行会随着流程推进不断更新。

举个例子:电商订单从「下单」到「支付」到「发货」到「签收」,每个阶段都有时间戳。用累积快照,一行就搞定:订单ID、下单时间、支付时间、发货时间、签收时间、当前状态。查询「平均从下单到签收要多久」时,直接算签收时间减下单时间,一行一个订单,快得飞起。

小技巧: 累积快照事实表通常用「开始时间」「结束时间」「最新状态」三个字段来标记流程进度。我习惯再加一个「流程天数」字段,提前算好,查询时直接 sum 就行。

适用场景:

  • 需要分析流程耗时(如订单履约时长、工单处理时长)
  • 需要跟踪流程当前状态(如哪些订单还在「待支付」)
  • 流程阶段固定,且每个阶段都有明确的时间点

避坑指南: 我曾经在一个物流项目里,用累积快照跟踪包裹流转。一开始只设计了 5 个阶段,后来业务加了 3 个新环节,结果表结构要改,历史数据要重刷——折腾了两周。所以,累积快照适合流程相对稳定的场景。如果流程经常变,建议用事务事实表加状态字段,或者用周期快照。

4.4 三种事实表的选择策略

实际项目中,这三种表不是选一个就行。我通常的做法是:事务事实表做明细查询,周期快照做汇总报表,累积快照做流程分析。三张表并存,各司其职。

举个例子,电商数据仓库:

  • 事务事实表: 订单明细表,每笔订单一行,用于分析用户行为、商品销售趋势
  • 周期快照: 每日订单汇总表,每天每个店铺一行,用于生成日报、月报
  • 累积快照: 订单履约进度表,每个订单一行,用于分析履约效率、异常订单

你想想看,如果只用事务事实表,查「昨天每个店铺的销售额」要扫描几百万行;用周期快照,直接读几千行。如果只用周期快照,查「某个订单现在到哪一步了」又得去翻明细。所以,按查询场景建不同的表,才是真正的性能优化。

核心原则: 查询什么粒度,就用什么粒度的事实表。不要试图用一张表满足所有查询。

4.5 一张图看懂三种事实表

下面这张图,帮你快速理清三种事实表的区别和选择逻辑。

三种事实表对比与选择 事务事实表 每笔事件一行 周期快照事实表 每个周期每个对象一行 累积快照事实表 每个流程实例一行 数据量大时 流程跟踪时 实际项目中,三张表通常并存:明细用事务,汇总用周期,流程用累积 选择逻辑 需要分析事件细节? → 事务事实表 (如每笔订单、每次点击) 需要周期性状态? → 周期快照事实表 (如每日库存、日终余额) 需要跟踪流程进度? → 累积快照事实表 (如订单履约、工单处理) 总结:没有银弹,按需组合 事务事实表 + 周期快照 + 累积快照 = 完整的数据仓库事实层

4.6 实战建议

最后,分享几个我踩过的坑和总结的经验:

  1. 不要一开始就建周期快照。 先跑事务事实表,等数据量上来了,发现查询慢了,再考虑加周期快照。过早优化是万恶之源。
  2. 累积快照的更新频率要控制好。 我见过有人每 5 分钟更新一次累积快照,结果表锁频繁,查询反而更慢。一般按业务节奏来,比如每天更新一次就够了。
  3. 三种表可以共享维度。 维度表设计好了,事实表随便换。这也是星型模型的好处——维度复用,事实表灵活。
  4. 别忘了清理历史数据。 事务事实表的数据量增长很快,超过一定时间范围的历史数据,可以归档到冷存储,或者直接删掉。我一般保留 90 天明细,更早的用周期快照替代。
一句话总结: 事务事实表管「发生了什么」,周期快照管「当时是什么状态」,累积快照管「现在到哪一步了」。搞清楚这三个问题,事实表设计就稳了。