4. 事实表设计优化:三种快照的场景选择
事实表设计,说白了就是回答三个问题:记录什么、多久记录一次、怎么记录变化。我做了这么多年数仓,见过太多因为事实表选型翻车的案例。今天咱们就聊聊事务事实表、周期快照事实表、累积快照事实表——这三种到底该怎么选。
核心观点:没有银弹。选哪种取决于你的业务场景是「看过程」「看状态」还是「看全貌」。
4.1 事务事实表:记录每一次「发生」
事务事实表,就是记录业务事件的每一行。比如下单、支付、退款,每发生一次就写一行。这是最基础、最常用的事实表类型。
适用场景:
- 需要分析单个事件的明细(比如某笔订单的金额)
- 事件之间没有强依赖关系
- 数据量可控,不需要频繁聚合
我个人的习惯是:只要业务方说「我要看每一笔交易的详情」,我第一反应就是事务事实表。但要注意,它有个致命弱点——无法直接反映状态变化。
避坑指南:我曾经接手过一个项目,业务方要求「统计每天有多少订单处于'已发货'状态」。结果他们用的事务事实表,每次发货都只记录一条新行。要算「当前已发货」还得去重、取最新状态……嗯,后来我给他们改成了周期快照。
4.2 周期快照事实表:定期「拍照」
周期快照事实表,就是按固定时间间隔(比如每天、每小时)记录业务对象的当前状态。它不关心中间发生了什么,只关心「这一刻是什么样」。
适用场景:
- 需要分析某个时间点的存量或状态(比如库存、账户余额)
- 业务状态变化频繁,但不需要逐笔追溯
- 数据量随时间线性增长,可控
举个例子:库存表。你不需要记录每一次入库出库的明细(那是事务事实表的事),你只需要知道每天结束时仓库里还剩多少货。周期快照就是干这个的。
注意:周期快照的粒度是「时间+维度」。比如每天每个仓库每个SKU一条记录。如果维度组合太多,数据量会爆炸。我见过一个项目,每天跑一次全量快照,结果一个月后表就几百亿行……后来改成了增量快照才救回来。
4.3 累积快照事实表:追踪「全生命周期」
累积快照事实表,专门用来追踪一个业务流程从开始到结束的完整生命周期。它只有一行记录,但这一行会随着流程推进不断更新。
适用场景:
- 需要分析流程耗时(比如订单从下单到签收花了几天)
- 流程有明确的开始和结束节点
- 需要同时看到多个里程碑的状态
我记得有个电商客户,他们想分析「从下单到发货平均需要多久」。如果用事务事实表,你得把下单、支付、发货、签收这些事件关联起来,写一堆复杂的SQL。用累积快照就简单了——每个订单一行,记录每个里程碑的时间戳,直接算差值就行。
关键设计:累积快照事实表通常包含多个日期字段(比如下单日期、支付日期、发货日期、签收日期),以及对应的状态字段。每次流程推进,就更新对应字段。
4.4 三种事实表的对比
为了让你看得更清楚,我整理了一张对比表:
| 维度 | 事务事实表 | 周期快照事实表 | 累积快照事实表 |
|---|---|---|---|
| 记录粒度 | 每笔事件 | 每个周期每个维度组合 | 每个流程实例 |
| 数据更新方式 | 只追加 | 覆盖或追加 | 更新已有行 |
| 典型场景 | 交易流水、日志 | 库存、余额、日活 | 订单生命周期、工单 |
| 查询特点 | 明细查询、聚合 | 时间点快照查询 | 流程耗时、里程碑分析 |
| 数据量 | 随事件量增长 | 随周期和维度增长 | 随流程实例增长 |
| ETL复杂度 | 低 | 中 | 高(需要处理更新) |
4.5 如何选择?一个决策框架
你可能会问:那我到底该用哪种?我一般按这个思路来:
- 先问业务问题:你要分析的是「事件」「状态」还是「流程」?
- 再看数据特征:数据是只增不减,还是需要更新?
- 最后评估成本:ETL复杂度、存储成本、查询性能,哪个是瓶颈?
举个例子:
- 如果业务方说「我要看每天有多少新用户注册」——用事务事实表,记录每次注册事件。
- 如果业务方说「我要看每天有多少活跃用户」——用周期快照,每天记录一次用户状态。
- 如果业务方说「我要看用户从注册到首次下单花了多久」——用累积快照,每个用户一行,记录注册时间和首次下单时间。
我的经验:很多时候,一个业务场景需要组合使用多种事实表。比如订单分析:事务事实表记录每笔交易,周期快照记录每天订单状态分布,累积快照追踪每个订单的完整生命周期。三者互补,才能覆盖所有分析需求。
4.6 三种事实表的逻辑关系
下面这张图展示了三种事实表在业务流程中的位置和关系:
4.7 实战中的常见误区
最后,分享几个我踩过的坑:
- 误区一:所有场景都用事务事实表。结果就是查询性能差,业务方要个「当前库存」都得跑几分钟。
- 误区二:周期快照的周期设得太短。比如库存每5分钟拍一次,数据量暴增,但业务根本不需要这么细的粒度。
- 误区三:累积快照的更新逻辑没处理好。我曾经遇到一个项目,ETL脚本没做幂等处理,导致同一行被重复更新,数据全乱了。
重要提醒:累积快照事实表的更新操作要格外小心。如果并发高,建议用「先查后改」或者「版本号」机制,避免数据覆盖。我一般会在累积快照里加一个last_updated时间戳,用来做冲突检测。
好了,三种事实表的选择就聊到这。记住:没有最好的事实表,只有最合适的。下次设计事实表时,先想清楚业务要什么,再动手。