事务事实表粒度:单事务、多事务与设计要点
聊到事实表粒度,我个人的经验是——粒度选对了,整个数仓就稳了一半。尤其是事务事实表,它记录的是业务系统里最细粒度的操作事件。你想想看,每一笔订单、每一次点击、每一笔转账,都是事务事实表的素材。
但问题来了:粒度到底该定多细?是每个事件一条记录,还是把多个事件揉在一起?这就是我们今天要聊的——单事务粒度和多事务粒度。
核心观点:事务事实表的粒度,决定了你能回答什么业务问题,也决定了数据量级和查询性能。选错了,后面改起来非常痛苦。
什么是事务事实表?
先简单回顾一下。事务事实表,记录的是业务系统中每个原子事件。比如:
- 电商:用户下单、支付、退款
- 金融:账户转账、ATM取款
- 物流:包裹扫描、签收
每条记录对应一个事件,时间戳精确到秒甚至毫秒。嗯,这里要注意——事务事实表通常是最细粒度的事实表,也是数据量最大的。
单事务粒度
单事务粒度,说白了就是一张事实表只记录一种业务事件。比如:
fact_order_create:只记录订单创建事件fact_order_pay:只记录订单支付事件fact_order_refund:只记录订单退款事件
每张表只关注一个动作,粒度非常清晰。
优点
- 理解简单:一张表对应一个业务动作,业务人员一看就懂
- ETL逻辑清晰:从源系统抽取、清洗、加载,流程很直白
- 查询性能好:表结构简单,索引容易设计
缺点
- 表数量多:业务事件多了,事实表数量也跟着膨胀
- 跨事件分析麻烦:想分析从下单到支付的转化率,得join多张表
我的经验:在电商项目中,我一开始用了单事务粒度,订单创建、支付、退款各一张表。后来业务方要分析“下单后多久支付”,每次都要join两张千万级的大表,查询慢得让人抓狂。后来我改成了多事务粒度,问题才解决。
多事务粒度
多事务粒度,就是把多个相关事件放在同一张事实表里。比如:
fact_order_transaction:同时记录订单创建、支付、退款、取消等事件
每行记录一个事件,但通过event_type字段区分不同的事件类型。
优点
- 表数量少:一张表覆盖多个业务事件
- 跨事件分析方便:同一个订单的不同事件都在一张表里,join操作少
- 维护成本低:只需要管理一张大表
缺点
- 表结构复杂:不同事件可能有不同的度量字段,需要设计通用字段或扩展字段
- 数据量大:所有事件都堆在一张表里,数据量会快速增长
- 查询可能变慢:如果过滤条件不当,全表扫描会很痛苦
| 对比维度 | 单事务粒度 | 多事务粒度 |
|---|---|---|
| 表数量 | 多 | 少 |
| 表结构 | 简单 | 复杂 |
| 跨事件分析 | 需要join | 直接查询 |
| 数据量 | 分散 | 集中 |
| 维护成本 | 高 | 低 |
| 适用场景 | 事件类型差异大 | 事件类型相似 |
事务粒度设计要点
好了,理论讲完了。接下来聊聊我在项目中踩过的坑,以及总结出来的设计要点。
要点一:明确业务过程
设计之前,先搞清楚业务方到底要分析什么。我曾经遇到一个需求,业务方说“我要看订单的全生命周期”。结果我设计了单事务粒度,他们每次都要join三张表。后来我改成多事务粒度,一张表搞定。
怎么判断?问自己三个问题:
- 业务方最常分析的维度是什么?
- 他们需要跨事件对比吗?
- 数据量级能接受吗?
要点二:控制粒度层级
粒度越细,数据越灵活,但数据量也越大。我见过一个项目,把用户每次页面滚动都记录成一条事务事实,结果一天就产生了10亿条数据。嗯,这显然过度设计了。
我的建议:粒度细到能回答业务问题就行,不要为了“万一以后要用”而过度设计。
要点三:设计事件类型字段
如果选择多事务粒度,一定要设计好event_type字段。我习惯用枚举值,比如:
event_type:
1 - 订单创建
2 - 订单支付
3 - 订单退款
4 - 订单取消
这样查询时可以直接过滤,性能更好。别用字符串,字符串查询慢,还容易出错。
要点四:处理不同事件的度量差异
不同事件可能有不同的度量字段。比如:
- 订单创建:订单金额、商品数量
- 订单支付:支付金额、支付方式
- 订单退款:退款金额、退款原因
我的做法是:通用字段放主表,特殊字段用扩展表或JSON字段。比如:
-- 主表
fact_order_transaction (
transaction_id,
order_id,
event_type,
event_time,
amount, -- 通用金额字段
quantity -- 通用数量字段
)
-- 扩展表(可选)
fact_order_transaction_ext (
transaction_id,
payment_method, -- 支付方式
refund_reason -- 退款原因
)
避坑指南:我曾经在一个项目里把所有度量字段都放在一张表里,结果表宽达到了200多列,查询性能极差。后来我拆成了主表和扩展表,性能才恢复正常。记住:表不要太宽,宽表不是万能的。
要点五:考虑数据生命周期
事务事实表的数据量增长很快。我建议:
- 热数据:近3个月的数据,放在高性能存储
- 温数据:3-12个月的数据,放在普通存储
- 冷数据:1年以上的数据,归档到低成本存储
这样既能保证查询性能,又能控制存储成本。
知识体系总览
下面这张图,帮你快速理清事务事实表粒度的核心逻辑:
总结一下
事务事实表的粒度选择,没有的对错。我的经验是:
- 事件类型差异大(比如订单和退款逻辑完全不同),用单事务粒度
- 事件类型相似(比如不同支付渠道的支付事件),用多事务粒度
- 不确定时,先选单事务粒度,后期可以通过视图或物化视图合并
记住:粒度设计是数仓的基石。选对了,后面一路顺畅;选错了,改起来成本极高。嗯,今天就聊到这里,希望对你有所帮助。