维度建模四步法:选业务过程、声明粒度、确认维度、确认事实
做数据仓库建模,我见过太多人一上来就画 ER 图,结果画到一半发现根本对不齐业务。其实有个更靠谱的套路——Kimball 老爷子总结的维度建模四步法。这四步我用了十几年,每次都能把混乱的需求理清楚。
说白了,就是四个问题:做什么?多细?从哪看?看什么?咱们一个一个拆。
核心口诀:先定过程,再定粒度,维度围绕业务转,事实跟着粒度走。
第一步:选业务过程
业务过程,就是业务里发生的一件事。比如电商的「下单」「支付」「发货」,银行的「开户」「转账」「放贷」。每个业务过程对应一个事实表。
我个人的习惯是,先跟业务方聊清楚:你们最关心的核心活动是什么?别一上来就想着把所有表都建了,那又回到烟囱式开发的老路上了。
我的经验:选业务过程时,优先选那些「有明确事件发生、有可度量数值、业务方天天盯着看」的过程。比如销售订单、客服工单、物流签收——这些是数据仓库的「现金牛」。
举个例子,一个电商平台的核心业务过程可能有:
| 业务过程 | 事件描述 | 典型事实 |
|---|---|---|
| 下单 | 用户提交订单 | 订单金额、商品数量 |
| 支付 | 用户完成付款 | 支付金额、支付手续费 |
| 发货 | 仓库发出商品 | 发货数量、物流费用 |
| 退货 | 用户申请退款 | 退款金额、退货数量 |
你看,每个过程都是独立的「事件快照」。把它们分开建模,后面做分析时才能灵活组合。
第二步:声明粒度
粒度,说白了就是一行数据代表什么。这是四步法里最容易翻车的一步。
我曾经在一个项目中,业务方说「我要看每天的销售汇总」,我就直接建了日汇总表。结果两周后他们又说「我要看每个订单的明细」——完蛋,粒度太粗,回不去了。只能重做。
血的教训:粒度一定要选最细的原子粒度。比如「每笔订单的每个商品行」,而不是「每天每个商品的汇总」。原子粒度可以向上聚合,但反过来不行。你想想看,是不是这个理?
常见的粒度声明方式:
- 事务粒度:每发生一次事件就一条记录。比如每笔支付、每次点击。
- 周期快照粒度:每个周期(如每天)每个实体一条记录。比如每日账户余额。
- 累积快照粒度:每个流程实例一条记录,记录其全生命周期。比如每个订单从下单到完成的全过程。
我个人建议,能用事务粒度就别用快照。事务粒度最灵活,能回答的问题最多。快照粒度虽然查询快,但一旦业务需求变了,你只能干瞪眼。
第三步:确认维度
维度就是看问题的角度。比如「哪个用户买的?」「什么时间买的?」「在哪个渠道买的?」——这些「谁、什么、何时、何地」就是维度。
确认维度时,有个简单的方法:对着粒度描述,把每个「修饰词」拎出来。比如粒度是「每笔订单的每个商品行」,那修饰词就有:订单号、商品ID、用户ID、下单时间、支付方式……这些就是维度。
维度建模的核心思想:事实表记录「发生了什么」,维度表描述「这件事的背景」。两者通过外键关联,形成星型模型。
常见的维度类型:
- 日期维度:几乎每个事实表都有。年、季、月、周、日、节假日……
- 产品维度:商品名称、品类、品牌、规格。
- 客户维度:姓名、等级、地区、注册时间。
- 门店/渠道维度:门店编号、区域、类型。
嗯,这里要注意:维度不是越多越好。我见过有人一张事实表挂了 30 多个维度,查询慢得要命,业务方还看不懂。一般 5-10 个维度就够用了,核心维度控制在 8 个以内。
第四步:确认事实
事实就是你要衡量的数值。比如金额、数量、时长、次数。事实必须跟粒度严格对齐——粒度是「每笔订单」,那事实就不能是「每天的总金额」。
事实分三种:
| 事实类型 | 说明 | 例子 |
|---|---|---|
| 可加事实 | 可以跨所有维度相加 | 销售金额、商品数量 |
| 半可加事实 | 只能跨部分维度相加 | 账户余额(不能跨时间相加) |
| 不可加事实 | 不能相加,只能做比率 | 单价、折扣率、利润率 |
我刚开始做建模时,总想把所有字段都塞进事实表。后来发现,事实表里只放度量值,描述性的东西全扔给维度表。这样事实表才「瘦」得下来,查询才快得起来。
避坑指南:我曾经在一个项目中,把「商品名称」也放进了事实表。结果商品改名后,历史数据全乱了。后来才明白——名称是维度属性,不是事实。事实只放数字,不放文本。
四步法实战:一个完整的例子
咱们拿「电商订单」来走一遍四步法:
- 选业务过程:「下单」——用户提交订单这个事件。
- 声明粒度:「每笔订单的每个商品行」——一条记录代表一个商品在一个订单里的购买行为。
- 确认维度:订单维度、商品维度、用户维度、时间维度、门店维度。
- 确认事实:商品数量、销售单价、折扣金额、实际支付金额。
你看,四步走完,模型结构就清晰了:
-- 事实表:订单明细事实
CREATE TABLE fact_order_detail (
order_sk INT, -- 订单维度外键
product_sk INT, -- 商品维度外键
customer_sk INT, -- 客户维度外键
date_sk INT, -- 日期维度外键
store_sk INT, -- 门店维度外键
quantity INT, -- 商品数量(可加事实)
unit_price DECIMAL, -- 单价(不可加事实)
discount_amt DECIMAL, -- 折扣金额(可加事实)
pay_amt DECIMAL -- 实付金额(可加事实)
);
这个模型,既能回答「昨天卖了多少钱」,也能回答「哪个商品卖得最好」,还能回答「哪个门店的折扣最大」。你想想看,如果一开始就做烟囱式的汇总表,能做到这么灵活吗?
总结一下:四步法不是理论空谈,是实打实的工程方法论。选对业务过程,定准粒度,配好维度,填对事实——数据仓库建模就成功了一大半。