订阅更新

事实表三种类型

数仓建模手册 第 4 题 约 4 分钟读完

本文目录
  1. 总结
  2. 事实表的核心:粒度
  3. 三种事实表对比
  4. 事务型事实表(最常见)
  5. 周期快照型事实表
  6. 累积快照型事实表

总结

记忆点内容
事实表第一步定义粒度(一行代表什么)
事务型一事件一行,不更新,最常见
周期快照型定期拍快照,记录状态,适合对比
累积快照型跟踪生命周期,会更新,实现复杂
实战要点同一业务域可以建多种事实表

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

基础 | 大数据面试 · 数仓建模系列

面试真题
事实表有哪几种类型?分别适用于什么场景?你们公司的订单表用的是哪种?

事实表的核心:粒度

设计事实表的第一步是定义粒度。粒度 = 一行数据代表什么。这个看似简单的问题,是很多数仓设计错误的根源。一笔订单?一次点击?一条日志?→ 事务型。每天的账户余额?每月的库存量?→ 周期快照型。一个订单从下单到签收的全过程?→ 累积快照型。

粒度定错,后面全是坑。我见过有人把订单表和订单明细表混在一起,一个订单买了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关联。」
关键:同一个业务域可以有多种事实表,服务不同的分析需求。这才是成熟的数仓设计思维。
刷题进度保存在当前浏览器