维度模型 详细介绍

📅 2026/6/20 16:15:23
维度模型 详细介绍
维度模型是数据仓库大师Ralph Kimball提出的一种面向分析的逻辑模型。其核心思想是:将数据组织成“事实”和“维度”两部分,通过星型或雪花型结构,提供高性能、易理解的查询体验。一、事实表(Fact Table)事实表存储业务过程的可度量的事件或指标(如销售额、数量、金额),以及关联维度表的外键。每一行对应一个业务事件或一个度量快照。1. 事实表的类型(按粒度划分)事实表有四种基本类型,适用于不同的分析场景:(1)事务事实表:记录每个业务过程的原子操作事件,以最细粒度保存每条事务。一旦事务提交,数据即插入且不再更改。适用于对灵活性和细节程度要求最高的分析场景,例如每一笔订单记录、每一笔支付记录。(2)周期快照事实表:按固定周期(每天、每周、每月)对某个状态拍快照。适用于需要跟踪存量或状态型指标的场景,比如“每月底的库存量”或“每天的账户余额”。它关注的是某个时间点上的累积状态,而非单次事务。(3)累积快照事实表:跟踪一个实体从开始到结束的整个生命周期,记录多个关键业务过程的日期和状态。典型的例子是订单全链路:创建订单 → 买家付款 → 卖家发货 → 买家确认收货,每个关键节点都作为字段存在同一行中,便于计算各环节的时间间隔。与事务事实表不同,累积快照事实表会随着业务过程的推进而被更新。(4)无事实的事实表:是一种特殊的事实表,它没有数值度量,只包含维度的外键组合,用于记录事件是否发生。每一行代表一个事实:某个组合的维度在某个时间点存在。学生考勤表:记录某天某学生是否出勤。快速选择指引:事务明细 → 事务事实表周期性状态 → 周期快照事实表业务流程跟踪 → 累积快照事实表仅记录存在性 → 无事实事实表2. 事实表的实现方式类型数据来源要点事务事实表来源于业务系统的事务表(ODS层),通常是按时间戳增量抽取加载方式:追加,不做历史更新。分区策略:按业务日期(如dt字段)分区,提升查询性能。周期快照事实表方式一:基于事务事实表聚合(如计算每月的交易情况汇总)。方式二:直接从源系统的状态表抽取(如每日末的账户余额表)。通常需要全量或增量计算(可维护前一日快照 + 当日增量的方式(拉链思想))。累积快照事实表事务事实表或业务流程日志(如订单的创建、支付、发货等事件)。需要能够跟踪同一业务流程实例的多个里程碑状态。每当流程推进到新里程碑时,更新该行的对应里程碑日期字段和状态字段。无事实的事实表来源A:维度组合的“覆盖关系”。例如学生选课:学生维度 × 课程维度,但只保留实际选课的组合。来源B:事件日志中仅记录“发生”而无数值的事件(如页面浏览,无金额)。没有度量列,或仅有一个常量列(如dummy = 1)以方便计数。加载方式:追加(事件型)或全量覆盖(关系型)。3.维度退化(Degenerate Dimension)退化维度是指原本应该作为维度的属性,因为本身没有更多描述信息,干脆直接留在事实表中,不为其单独建立维度表。展开来讲,满足以下条件时,就适用维度退化策略:条件 1:它是业务操作产生的“自然键”这个标识符不是数据仓库生成的代理键,而是来自源系统的业务单据号码,比如交易流水号、订单号、发票号、运单号、支付流水号等。条件 2:它除了自己,没有其他描述信息这是最核心的判断点。你可以问自己:如果为这个字段单独建一张维度表,表里除了这个 ID 本身,还能有什么列?如果答案几乎是“什么都没有”,那它就适合退化。 比如:订单号 —— 没有任何“订单号类别”“订单号状态”这类有意义的属性(订单自身的状态是事实,不是订单号的属性)。核心区分:标识的属性 vs. 业务的属性A类. 用来描述“订单号这个符号本身”的属性 这指的是独立于任何业务含义,纯粹描述这个字符串物理或逻辑特征的属性。比如:这个号码是几位数?它是什么编码规则生成的?它属于哪种单据类型?结论:对于订单号,这类属性几乎永远不存在或无需分析。B类. 用来描述“订单这个业务事件”的属性 这指的是订单这个业务事件的属性:订单金额、下单时间、订单状态、支付方式、收货地址、用户ID等等。结论:这些都不是订单号的属性,而是订单本身的属性。退化维度的判断准则,针对的是A类属性。一个标识符之所以被“退化”,是因为它在仓库中找不到能作为“维度属性”存在的A类信息。条件 3:它在事实表中几乎就是“主键”退化维度通常和事实表的粒度高度对应:在事务事实表中,它往往就是该业务事件的唯一标识(或组合唯一标识的一部分),例如一笔交易记录对应一个交易流水号。在累积快照事实表中,它是跟踪整个生命周期的业务主键(如一个订单号贯穿全部里程碑),每一行代表一个业务实例。条件 4:分析时需要用它做分组、过滤、钻透退化维度虽然不参与求和,但常常是 BI 用户下钻最细粒度明细的入口,比如“按订单号查询所有明细”“追踪某个运单的全链路状态”。这种场景下直接用它过滤,远比 Join 一张空洞的维度表高效。举例:字段是否退化维度?理由订单号✅ 是只有号码本身,没有任何有意义的描述属性,且在分析中频繁用于分组和下钻。用户 ID❌ 不是用户有姓名、性别、城市、注册时间等丰富属性,必须建维度表。支付流水号✅ 是只有一串数字,无其他属性,且常作为对账的关键标识。商品 ID❌ 不是商品有名称、类目、品牌、规格等属性,需要维度表承载。