【从零开始学习数据仓库 | 第一篇】:维度建模理论

本文系统讲解数据仓库维度建模的关键理论,涵盖OLTP与OLAP本质差异、维度表与事实表的分工、自然键与代理键的设计意义、事实表的可加性分类(可加/半可加/不可加)、三种事实表(事务型/周期快照/累积快照)适用场景,以及维度设计的核心原则。强调维度建模对分析性能、历史追溯和业务语义统一的基础支撑作用。

写在前面:这是我学习数仓系列记录的第一篇,我会把每天学习时对工作重要的,难理解的东西记录下,我试着把 Kimball 维度建模的核心概念串成一条线——从“为什么数仓必须独立存在”讲起,再落到维度表、事实表、代理键、可加性这些基础零件上。文中会穿插一些我自己的理解方式,不一定严谨。


一、OLTP 与 OLAP:为什么数仓必须独立存在

刚接触数仓时我有个疑问:业务库好好的,为什么不能直接拿来做分析?答案藏在两类系统的基因差异里。

OLTP(联机事务处理) 的设计目标是“快而准地处理每一笔交易”。它高度规范化,同一个客户信息只存一份,更新时只改一个地方。这在写入场景下很高效,但一旦面对“统计上个月华东地区所有品类销售额”这类查询,就需要把十几张规范化表 Join 起来,慢得让人绝望。

OLAP(联机分析处理) 的设计目标恰恰相反:让分析查询跑得快。它采用维度建模,把数据组织成星型或雪花型,适度反规范化,用冗余换取更少的 Join 和更快的聚合。而且分析往往要回溯历史,OLTP 库如果为了性能定期清理旧数据,分析就没法做了。

更现实的问题是资源争抢。一条扫描几百万行的分析查询扔到业务库上,会直接拖慢用户的正常下单和支付。所以数仓独立存在,本质上是在保护交易系统的稳定性,同时给分析工作一个按分析场景优化过的环境。这不是架构上的奢侈,是工程上的必要。


二、数仓 vs 数据库:不只是名字不同

把“数仓”和“数据库”混着叫,是我入门时最常犯的错。现在我会这样区分:

数据库(偏 OLTP) 关心的是“当前这一刻,这笔订单的状态是什么”。它追求事务的 ACID,数据是规范化的,保留的是最新的、一致的状态快照。

数据仓库(偏 OLAP) 关心的是“过去三年,这类订单的趋势是什么”。它追求的是查询吞吐和聚合效率,数据是反规范化的,保留的是完整的历史轨迹。一个客户搬了三次家,OLTP 库里只有最新地址,但数仓里可能有三条记录,分别对应他每次下单时所在的地址。

另外,数仓是面向主题的。业务库按“订单表、用户表、商品表”这样按功能划分,数仓则按“销售主题、库存主题、用户行为主题”来组织,把散落在多个业务系统里、关于同一主题的数据集成到一起。这种集成本身就需要清洗、去重、统一口径,不是简单复制能完成的。


三、维度表与事实表:数仓的两块基石

维度建模把所有表分成两类,这个二分法极其简洁,但足以覆盖绝大多数分析场景。

事实表记录的是“发生了什么”。每一行对应一个业务事件(一次下单、一笔支付、一条库存快照),里面装的是可度量的数字,比如金额、数量、次数。事实表通常又窄又长,行数可以大到千亿级。

维度表描述的是“谁、什么、哪里、何时”。它给事实表里的数字提供上下文。比如事实表里有一行“2024-03-15,客户123,商品456,买了2件,花了199元”,维度表负责告诉你:客户123住在杭州、是金卡会员;商品456属于户外运动品类、是某个品牌的帐篷;2024-03-15是周五、属于第一季度。

我自己的记忆方法是:事实表是“动词+数字”,维度表是“名词+描述”。事实表回答“多少”,维度表回答“关于什么”。


四、自然键 vs 代理键:为什么维度表需要两个身份证

维度表里通常有两个“键”,一开始我觉得这是冗余,后来才明白各自的分工。

自然键(也叫业务键)是业务系统里本来就有的标识,比如订单号、身份证号、商品编码。它来自源系统,对人友好,但有个致命问题:可能变,也可能重复。比如商品编码在系统升级时改规则了,或者两个源系统的客户 ID 撞号了。

代理键是数仓自己生成的、无业务含义的整数(通常自增)。它唯一的职责就是在数仓内部唯一标识一行。用代理键做 Join 有几个实际好处:整数比字符串 Join 快;源系统的键变了不影响数仓;更重要的是,它支持缓慢变化维度——同一个客户因为搬家产生了三条历史记录,自然键都是同一个身份证号,但代理键分别是 101、102、103。这样,搬家前下的单关联的是 101,搬家后关联的是 102,历史归属就保住了。

我的理解是:自然键是“给业务看的”,代理键是“给数仓自己用的”。


五、关于“维度设计六原则”的说明

Kimball 原著和主流实践里并没有一个被广泛公认的、固定编号的“六原则”。不同团队会根据自己的经验总结出不同条数。结合常见实践,大致可以归纳为:

  1. 原子性:维度属性尽量不可再分,日期就存日期,不要存“2024年3月”这种混合值。
  2. 一致性:同一个业务概念在不同维度表里的命名、类型、枚举值必须统一,否则跨主题分析会错。
  3. 可理解性:属性用文字描述而非编码,让业务用户能直接看懂。
  4. 适当冗余:为了少 Join,维度表可以反规范化,把层次属性打平放在同一张表里。
  5. 可扩展性:预留未来可能增加的属性位置,避免频繁改表。
  6. 代理键独立:维度表必须有代理键,与业务键分离。

需要说明,这不是金科玉律,更像是一个检查清单。不同书和文章里的“原则”条目差异很大,不必纠结于数字。


六、事实的三种可加性

事实表里的数字,不是都能随便相加的。这个区分在做汇总时至关重要。

可加事实:可以沿任意维度相加。销售额、数量、次数,怎么加都对。

半可加事实:只能沿部分维度相加,最典型的是余额。你可以把同一天所有账户的余额加起来(沿账户维度可加),但不能把一个账户一个月的余额加起来(沿时间维度不可加,那没有意义)。

不可加事实:任何维度都不能直接相加,比如比率(转化率、毛利率)。处理办法是拆成分子和分母分别存储,让它们变成可加事实,使用时再相除。比如不存“转化率 3%”,存“曝光 1000 次,转化 30 次”。

这个知识点看起来小,但在实际做报表时,直接把比率字段 sum() 起来是最常见的错误之一。


七、三种事实表:对应三类业务节奏

事实表按业务过程的时间特性,分成三种。我一开始分不清后两种,后来用“一个事件 vs 一个周期 vs 一个生命周期”来记,就清楚多了。

事务事实表是最基础的。业务发生一次,插入一行,只插入,不更新。下单、支付、点击、退款,每个原子事件一行。粒度最细,灵活性最高。

周期快照事实表按固定周期(天/周/月)记录状态。比如每天日终的库存余额、每月末的账户余额。它不是记录“发生了什么变化”,而是记录“在那一时刻,状态是什么”。同样只插入,不更新,但粒度是“实体 × 周期”。

累积快照事实表最特殊,它跟踪一个实体的完整生命周期。一个订单从创建、付款、发货到签收,在累积快照表里是同一行,随着流程推进不断被 UPDATE,不同阶段的日期填进不同字段。它的价值在于能直接算出“下单到付款平均间隔多久”这类跨阶段指标。

三种表的核心区别:

事务事实表周期快照事实表累积快照事实表
一行代表一个事件一个实体在一个周期内的状态一个实体的完整生命周期
写入方式只插入只插入插入后更新
时间字段单一事务时间单一快照时间多个里程碑时间

写在最后

这篇笔记梳理了维度建模最底层的几个概念。我的体会是:维度建模的价值不在于概念多精妙,而在于它强迫你在动手写 SQL 之前,先把“业务过程是什么、粒度是什么、谁在分析什么”想清楚。代理键、可加性、三种事实表,这些看似琐碎的规则,每一条背后都有真实的踩坑教训。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值