粒度选择核心原则:原子粒度、业务过程对齐、不可再分

好,咱们进入正题。事实表粒度怎么选?我这些年踩过的坑,总结下来就三条核心原则。你把这三点吃透了,80% 的场景都不会跑偏。

说白了,粒度选择就是回答一个问题:「这张事实表的一行,到底代表什么?」 答案对了,后面星型模型、汇总表都好办。答案错了,嗯,等着重构吧。

原则一:原子粒度原则

原子粒度,就是最细的、不可拆解的业务事件级别。我习惯叫它「打回原形」原则。

举个例子。你在电商公司,订单表里存了「订单金额 500 元,包含 3 件商品」。这算原子粒度吗?不算。 因为一行里包含了多个商品,你没法单独分析「某件商品的销量」。必须拆成三行,每行一个商品子项。

核心判断标准: 事实表的一行,是否对应业务系统中一次不可再分的操作记录?

我在项目中遇到过最典型的反例:某金融客户把「用户当日所有交易汇总」作为一行存入事实表。结果分析师想查「单笔超过 5 万的交易」,根本查不了。为什么?因为粒度已经被汇总操作污染了。

我的习惯: 设计阶段先问业务方「你们最细的记录长什么样?」拿到原始日志或流水表,再开始建模。不要从汇总需求倒推粒度。

原则二:业务过程对齐原则

这条原则说的是:一张事实表,只服务于一个业务过程。

你想想看,下单是一个过程,支付是另一个过程,退款又是独立的。把它们塞进同一张表,维度关联会乱成一锅粥。我曾经接手过一个遗留系统,一张「交易事实表」里同时包含了下单、支付、发货、签收四个过程的状态字段。结果呢?每次取数都要写一堆 CASE WHEN 来区分当前行到底代表哪个过程,维护成本极高。

正确的做法是拆成多张事实表:

业务过程 事实表名称 粒度描述
用户下单 订单事实表 每行一个订单商品子项
支付完成 支付事实表 每行一次支付流水
物流发货 发货事实表 每行一个包裹发货记录
用户退款 退款事实表 每行一次退款申请

这样做的好处很明显:每张表的维度关系清晰,度量字段纯粹,ETL 逻辑也简单。分析师拿到表就知道「哦,这张表是管支付的」,不用猜。

避坑指南: 我曾经见过有人把「下单」和「支付」强行放在一张表里,用 NULL 表示未支付的行。结果全表扫描时性能极差,而且维度外键经常对不上。记住:一个业务过程一张事实表,别贪心。

原则三:不可再分原则

这条是原子粒度的延伸。它强调:事实表的每一行,在业务语义上不能再往下拆了。

怎么判断?问自己一个问题:如果把这一行再拆成两行,业务上还有意义吗?

举个例子。某零售企业的事实表里有一行:「门店 A 在 2024-01-01 销售了 10 箱矿泉水,总价 200 元」。这能再分吗?可以。如果矿泉水有不同规格(500ml 和 1.5L),那这一行就应该拆成两行。但如果门店的销售系统只记录了「整箱销售」,没有更细的规格信息,那这一行就是不可再分的。

关键判断: 不可再分不是的「物理上不能再分」,而是「业务源系统能提供的最细粒度」。源系统只给到「天」,你就别强行拆到「小时」。

我个人的经验是:先按源系统的最细粒度建模,等业务方提出更细粒度的需求时,再通过增加维度或拆分事实表来扩展。 不要一开始就猜测更细的粒度,那往往会导致过度设计。

三条原则的关系

这三条原则不是孤立的。原子粒度是基础,业务过程对齐是组织方式,不可再分是校验标准。我习惯用一张图来帮团队理解:

粒度选择三原则关系图 事实表粒度 原子粒度原则 最细业务事件级别 业务过程对齐原则 一表一过程 不可再分原则 业务语义上不可拆 三者关系 原子粒度是基础,业务过程对齐决定表结构 不可再分是最终校验标准,三者缺一不可

从图里你能看到:原子粒度决定了「一行有多细」,业务过程对齐决定了「哪些度量放一起」,不可再分则帮你检查「有没有拆过头或没拆够」。三者形成一个闭环。

实战中的优先级

如果遇到冲突怎么办?比如原子粒度和业务过程对齐看起来矛盾了。我建议的优先级是:

  1. 先保原子粒度 —— 这是数据可信度的底线。粒度不够细,后续所有分析都受限。
  2. 再按业务过程拆分 —— 原子粒度确定后,把不同过程的度量分到不同事实表。
  3. 最后用不可再分校验 —— 检查每张表的每一行是否还能继续拆分。

一个小技巧: 设计完成后,找业务方拿三个最典型的查询需求,用你的事实表去跑一遍。如果都能直接命中粒度,说明选对了。如果某个查询需要先聚合再过滤,那粒度可能偏细了;如果需要先拆解再计算,那粒度可能偏粗了。