事实表三种类型
总结
| 记忆点 | 内容 |
|---|---|
| 事实表第一步 | 定义粒度(一行代表什么) |
| 事务型 | 一事件一行,不更新,最常见 |
| 周期快照型 | 定期拍快照,记录状态,适合对比 |
| 累积快照型 | 跟踪生命周期,会更新,实现复杂 |
| 实战要点 | 同一业务域可以建多种事实表 |
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
基础 | 大数据面试 · 数仓建模系列
| 面试真题 事实表有哪几种类型?分别适用于什么场景?你们公司的订单表用的是哪种? |
|---|
事实表的核心:粒度
设计事实表的第一步是定义粒度。粒度 = 一行数据代表什么。这个看似简单的问题,是很多数仓设计错误的根源。一笔订单?一次点击?一条日志?→ 事务型。每天的账户余额?每月的库存量?→ 周期快照型。一个订单从下单到签收的全过程?→ 累积快照型。
粒度定错,后面全是坑。我见过有人把订单表和订单明细表混在一起,一个订单买了3件商品就变3行,金额直接算重复了。所以在写第一行SQL之前,先在文档里写清楚:一行等于什么。
三种事实表对比
| 类型 | 粒度 | 特点 | 典型场景 |
|---|---|---|---|
| 事务型 | 一次业务事件 | 只记录发生的事实,不更新 | 订单表、点击日志、支付记录 |
| 周期快照型 | 固定时间周期 | 每个周期一条,反映状态 | 每日库存、每日活跃用户数 |
| 累积快照型 | 业务全生命周期 | 一行多个里程碑,会更新 | 订单履约(下单→签收) |
事务型事实表(最常见)
每发生一次业务事件,就新增一行,插入后不再修改。这是最简单也最常见的类型。数据量最大(每天只增不改),适合回答「发生了什么」:今天有多少订单、GMV多少。但不适合回答「当前状态是什么」:比如当前有多少未发货订单。
| Wood的实战经验 我们短剧出海业务的广告点击表就是典型的事务型事实表,每天几千万条点击记录,只追加不更新,按天分区存储。对于这种数据量大且只追加的场景,分区策略非常重要——我们按dt(日期)做一级分区,按region做二级分区,这样查某一天某个地区的数据时性能提升100倍以上。 |
|---|
周期快照型事实表
每隔固定时间(天/周/月)拍一个快照,记录那个时间点的状态。每个周期一行,数据量可控。注意:即使那天没有事件发生,也会有一条快照记录——这是和事务型的关键区别。
什么时候用?当你需要对比不同时间点的状态时。比如「用户上周的余额和这周对比」,事务型做不到(只记录了充值/消费事件),快照型直接查两天的快照就行。
典型场景:每日用户活跃快照(user_id + active_days_7d + total_orders + account_balance + snapshot_date)。
累积快照型事实表
一行记录一个业务实体的完整生命周期,包含多个里程碑时间(下单时间、支付时间、发货时间、签收时间),行会被更新。适合分析流程效率:下单到支付平均多久?发货到签收多久?
实现复杂度最高,需要处理更新逻辑。在离线数仓里一般用INSERT OVERWRITE实现更新,不是真的UPDATE。每天全量或增量重跑,用COALESCE合并新旧数据。
| 面试加分提示 面试官追问「你们订单表用的哪种」时,高分回答是说出你用了多种: 「我们订单相关有两张事实表:一张事务型的fact_order_detail,记录每笔交易明细,粒度是订单+商品,用于GMV、客单价分析;一张累积快照型的fact_order_lifecycle,跟踪订单从创建到签收的全流程,用于履约效率分析。两张表通过order_id关联。」 关键:同一个业务域可以有多种事实表,服务不同的分析需求。这才是成熟的数仓设计思维。 |
|---|