Kimball维度建模技术概述
记录一下读《数据仓库工具箱》时的思考,摘录一些书中关于维度建模比较重要的思想与大家分享🤣🤣🤣
第二章前言部分作者提到:技术的介绍应该通过涵盖各种行业的熟悉的用例展开(赞同哈哈 确实比抽象地讲解概念要好理解🤣🤣🤣)。
书中从第三章开始是通过各行业的用例去讲解维度建模,第二章则是维度建模技术的总体介绍(很多概念,挺抽象的🤣🤣🤣)。
前言部分作者也有提到:我们并不期望您一开始就从头到尾阅读本章,但希望您能将本章作为所提供的技术参考。本节介绍的技术,在所有维度设计工作中都需要考虑。本书的每一章几乎都会涉及本节所介绍的概念。
01、基本概念
02、事实表技术基础
书接上回~🤣🤣🤣🤣🤣🤣
Kimball维度建模技术概述
- Kimball维度建模技术概述
- 2.3 维度表技术基础
- 2.3.1 维度表结构
- 2.3.2 维度代理键(Surrogate Key)
- 2.3.3 自然键、持久键和超自然建
- 2.3.4 下钻
- 2.3.5 退化维度
- 2.3.6 非规范化扁平维度
- 2.3.7 多层次维度
- 2.3.8 文档属性的标识与指示器
- 2.3.9 维度表中的空值属性
- 2.3.10 日历日期维度
- 2.3.11 扮演角色的维度
- 2.3.12 杂项维度
- 2.3.13 雪花维度
- 2.3.14 支架维度
- 整理不易,列位一键三连,谢谢支持~🤣🤣🤣
2.3 维度表技术基础
2.3.1 维度表结构
维度表(Dimension Table) 用于存储描述性信息(维度属性),为事实表提供上下文支持。
维度表结构通常围绕某个分析维度组织,如客户、产品、时间、地区等。
- 粒度清晰🍕:每条记录代表一个唯一的维度实体,粒度必须清晰(如每个客户、每个产品)。
- 主键唯一🍔:维度表的主键是每个维度实体的唯一标识,通常称为代理键(Surrogate Key)。
- 描述性属性🍟:维度表的列通常包含详细的描述信息,用于为事实表提供上下文。
- 数据量小🍿:相对于事实表,维度表的数据量通常较小,但可能包含丰富的属性字段。
- 变化管理🥓:维度表需要管理属性值的历史变化(例如,采用缓慢变化维度策略)。
维度表的主要字段
字段类别 | 说明 |
---|---|
代理键(Surrogate Key) | 维度表的主键,用于唯一标识维度记录,通常是系统生成的数字或UUID。 |
业务键(Business Key) | 来源系统的唯一标识符(如客户ID、产品SKU等),用于追踪源数据。 |
描述属性 | 描述维度实体的属性,如客户的姓名、产品的类别等,用于丰富分析的上下文。 |
分组属性 | 用于分类的字段,如产品类别、地理区域等,方便聚合分析。 |
时间属性 | 用于标记或分析维度实体的时间变化,例如产品的上市日期、客户的注册日期等。 |
2.3.2 维度代理键(Surrogate Key)
维度代理键 是在维度表中用于唯一标识每条记录的人工生成的键,通常是一个简单的数字或唯一标识符(UUID)。代理键与事实表中的外键相对应,用于实现事实表和维度表之间的关联。
- 唯一性:每条记录都有唯一的代理键,用来区分不同的维度实体。
- 系统生成:代理键通常由数据仓库系统生成,而不是从源系统继承的业务键。
- 稳定性:即使源系统中的业务键发生变化,代理键仍然保持不变。
- 效率高:代理键通常为整数类型(如
INT
或BIGINT
),占用存储空间小,性能高。
Demo😋😋😋:
代理键(Surrogate Key) | 客户ID(业务键) | 客户姓名 | 性别 | 城市 | 注册日期 |
---|---|---|---|---|---|
1 | CUST001 | Alice | Female | New York | 2023-01-10 |
2 | CUST002 | Bob | Male | Los Angeles | 2023-03-15 |
3 | CUST003 | Charlie | Male | Chicago | 2023-06-20 |
- 代理键 (
1
,2
,3
) 是系统生成的,与源系统无关。 - 业务键 (
CUST001
,CUST002
,CUST003
) 来自源系统,用于表示客户的原始标识。
代理键的优点
- 避免业务键变动的影响😋:源系统的业务键(如产品SKU或客户ID)可能会发生变更,而代理键的稳定性确保了数据仓库的结构不受影响。
- 支持缓慢变化维度(SCD)😎:当维度属性发生变化时,代理键可以区分不同版本的记录,帮助跟踪历史数据。
Demo🤣🤣🤣:
- 当客户的地址发生变化时,可以新增一条记录,并分配新的代理键。
代理键 | 客户ID(业务键) | 客户姓名 | 性别 | 城市 | 生效开始日期 | 生效结束日期 |
---|---|---|---|---|---|---|
1 | CUST001 | Alice | Female | New York | 2023-01-10 | 2023-05-01 |
2 | CUST001 | Alice | Female | Boston | 2023-05-02 | NULL |
- 第一条记录表示客户 Alice 在 New York 的历史状态。
- 第二条记录表示客户 Alice 在 Boston 的当前状态。
- 使用代理键(
1
和2
)可以区分这些不同的状态,而业务键(CUST001
)仍然一致。
- 提高查询效率:代理键的数值型特性比复杂的业务键(如字符串类型)更适合索引和连接操作。
- 支持多源数据集成:当维度数据来源于多个不同的源系统时,代理键可以统一标识不同来源的数据。
代理键的生成方式
- 自动递增数字:最常见的方法,通常由数据库的自动增量机制(如
AUTO_INCREMENT
)生成。 - UUID:全局唯一标识符,适用于分布式数据仓库,但存储空间和查询效率较低。
- 批量生成:通过ETL工具在加载数据时批量生成代理键。
代理键和业务键的区别
代理键 | 客户ID(业务键) | 客户姓名 | 性别 | 城市 | 生效开始日期 | 生效结束日期 |
---|---|---|---|---|---|---|
1 | CUST001 | Alice | Female | New York | 2023-01-10 | 2023-05-01 |
2 | CUST001 | Alice | Female | Boston | 2023-05-02 | NULL |
-
代理键(Surrogate Key):
- 由系统生成,通常是整数类型。
- 在数据仓库中作为维度表的主键,用于连接事实表。不受源系统数据变化的影响。
-
业务键(Business Key):
- 来源于源系统,表示业务实体的唯一标识(如产品ID、客户ID等)。
- 在数据仓库中用于追踪和映射源系统数据。
为什么使用代理键实现事实表和维度表之间的关联,而不是业务键?
-
稳定性:
- 业务键来自源系统,但可能会发生变化,例如产品ID或客户ID因为业务调整而修改。
- 代理键是系统生成的唯一标识,独立于源系统,具有更高的稳定性和一致性。
-
效率:
- 业务键通常是字符串类型(如
P12345
或CUST001
),占用存储空间较大,连接操作效率较低。 - 代理键通常是整数类型(如
INT
或BIGINT
),在存储和查询时更高效,尤其适合数据量大的事实表。
- 业务键通常是字符串类型(如
-
缓慢变化维度(SCD)的支持:
- 如果使用业务键作为关联,当维度数据发生变化(如客户地址变更)时,难以保留历史版本。
- 使用代理键,可以在维度表中为同一个业务键生成多个版本记录,从而轻松跟踪历史数据。
-
多源系统的数据集成:
- 不同源系统可能使用不同的业务键格式(如客户ID在一个系统中是数字,在另一个系统中是字符串)。
- 通过引入代理键,可以统一不同源系统的数据。
Demo🤣🤣🤣:
产品维度表 (dim_product
)
product_sk (代理键) | product_id (业务键) | product_name | category | price |
---|---|---|---|---|
1 | P1001 | “Laptop X1” | Electronics | 1500.00 |
2 | P1002 | “Smartphone Z” | Electronics | 800.00 |
销售事实表 (fact_sales
)
sale_id | product_sk (外键) | quantity_sold | sale_date |
---|---|---|---|
1001 | 1 | 10 | 2023-12-10 |
1002 | 2 | 5 | 2023-12-10 |
dim_product
表的product_sk
是代理键(系统生成)。fact_sales
表通过外键product_sk
关联到dim_product
表。
为什么不用 product_id
直接关联?
- 如果
product_id
(业务键)在源系统中发生变化,例如从P1001
改为PROD1001
,这种变更会导致事实表中记录失效,关联关系断裂。 - 代理键保持稳定,即使业务键发生变化,只需在维度表中更新即可,而不影响事实表的外键关系。
2.3.3 自然键、持久键和超自然建
- 自然键(Natural Key)
自然键是指在操作型系统中已经存在的、能够唯一标识实体的键。它直接来源于业务规则和现实世界的唯一标识符,例如雇员号、产品编号、订单号等。
- 自然键受业务规则的影响,且通常无法被数据仓库(DW/BI系统)控制。
- 在某些情况下,自然键可能会发生变化,比如雇员辞职后重新回到公司,系统会为其分配新的雇员号。
- 这种变化对于数据仓库来说会带来问题,特别是当我们需要跨时间段跟踪和汇总历史数据时。
- 持久键(Surrogate Key)
为了应对自然键的变化,数据仓库使用持久键🤣🤣🤣。
持久键是一种由数据仓库系统人工生成的唯一标识符,通常是递增的整数或其他类型的唯一标识符。
持久键的设计独立于业务过程,它并不依赖于业务规则,因此可以保持不变,即使业务中的自然键发生变化。
Demo🤣🤣🤣:
雇员维度表
员工_SK(持久键) | 员工_ID(自然键) | 员工姓名 | 状态 | 入职日期 | 离职日期 |
---|---|---|---|---|---|
1 | 101 | 张三 | 在职 | 2010-01-01 | NULL |
2 | 102 | 李四 | 在职 | 2012-03-15 | NULL |
3 | 101 | 张三 | 离职 | 2015-01-01 | 2016-01-01 |
4 | 103 | 王五 | 在职 | 2016-04-10 | NULL |
5 | 201 | 张三 | 在职 | 2017-06-01 | NULL |
-
持久键的“不会变化”是指它在数据仓库中始终保持唯一性和稳定性,而不是在每次记录的变化(如状态变化、重新入职)时都变。每条记录的持久键始终标识那条特定的记录。
-
不同的记录(例如同一员工的入职、离职、再入职)会得到不同的持久键,以确保数据的完整性。
- 持久性超自然键(Persistent Surrogate Key)
持久性超自然键这个术语,实际上就是对持久键进一步描述的一个补充。强调了持久键的持久性和超自然特性。
在数据仓库中,当某个实体(如雇员、客户等)在多个生命周期中有多个自然键变动时,持久键依然保持不变,始终指向同一实体。
- 格式独立于业务过程:持久键的值(通常是整数)不受业务规则或实际应用场景的限制,它是完全独立的。例如,一个雇员的持久键可能是递增的整数
1, 2, 3…
,这些值与实际的雇员号码无关。 - 递增分配:持久键通常从整数
1
开始递增,确保每条记录有唯一标识符,并且在整个数据仓库中唯一。
2.3.4 下钻
下钻是从较高的聚合层次(汇总数据)进入更详细的层次(如具体记录)的过程。
Demo🤣🤣🤣:
对销售数据集进行分析,数据以地区、时间、产品类别等维度进行汇总。
- 高层次:首先看到的是整个国家的销售总额。
- 下钻:可以选择“按省份”来查看销售数据,进一步细分到每个城市的销售额,甚至深入到具体的每个销售订单。
- 进一步下钻:按“产品类别”或者“销售人员”等维度,查看更细粒度的数据。
年份 | 季度 | 总销售额 |
---|---|---|
2024 | Q1 | 100万元 |
2024 | Q2 | 150万元 |
2024 | Q3 | 200万元 |
2024 | Q4 | 180万元 |
-
从总销售额下钻到季度:2024年的销售总额汇总为630万元,然后可以选择按季度进一步查看销售数据。
-
从季度下钻到月度:可以选择进一步下钻到每个季度的月度销售额。
-
从月度下钻到具体销售订单:如果希望深入了解某个月或某个产品的具体订单情况,可以继续下钻到具体的销售记录。
Tips:
- 上卷(Drill-up)🤣🤣🤣:与下钻相对,上卷是指从较低层次的数据返回到更高层次的聚合信息。比如,在月度数据下钻到季度或年度时,可以通过“上卷”查看汇总的季度或年度数据。
2.3.5 退化维度
退化维度(Degenerate Dimension,简称DD)是数据仓库设计中的一个概念,通常用于事实表(Fact Table)中的维度列。
退化维度并不是指一种独立的维度表,而是指那些在事实表中作为维度存在,但没有单独维度表来描述的维度。😂
退化维度是直接存储在事实表中的维度,它不需要独立的维度表,因为它没有复杂的属性结构或层次。🤓
退化维度可以简化数据仓库的设计,减少不必要的表和关联,同时提高查询效率。
Tips:
- 不需要独立维度表:退化维度通常只是某个业务过程中的一些关键字段,虽然它们像维度一样存在于事实表中,但没有单独的维度表来存储详细信息。
- 简单性:这些维度通常非常简单,且通常不会变化,适合直接存储在事实表中。
- 没有层次结构:退化维度没有复杂的层次结构或属性,因此不需要单独的维度表来维护。
Demo🤣🤣🤣:
退化维度通常用于那些在业务操作中需要频繁访问,但又不需要额外描述的字段。
- 订单编号:在零售、物流或电商数据仓库中,订单编号通常是事实表中的一个字段,作为客户交易的唯一标识。它没有额外的属性,也不需要进一步分解,因此不需要建立单独的维度表。
- 发票编号:财务数据仓库中,发票编号常作为事实表的字段,记录交易或支付的具体编号。这些编号本身通常没有多层次的描述,且通常直接与事实表关联。
销售事实表:
销售ID(Sale_ID) | 订单编号(Order_ID) | 销售金额(Sale_Amount) | 销售日期(Sale_Date) |
---|---|---|---|
1 | 1001 | 2000 | 2024-12-01 |
2 | 1002 | 1500 | 2024-12-02 |
3 | 1003 | 5000 | 2024-12-03 |
订单编号(Order_ID)就是一个退化维度。它代表了每个销售交易的唯一标识符,但不需要单独为其建立维度表,因为它本身没有更多的层次或属性(除了作为订单的唯一标识符)。
Tips:
-
避免重复和冗余:虽然退化维度在事实表中直接存储,但要确保这些字段不会引起数据冗余或重复。退化维度通常是唯一的标识符。
-
提高查询效率:将这些字段作为退化维度存储在事实表中,可以提高查询性能,因为查询可以直接通过事实表检索数据,避免了多表连接。
-
简单且稳定的维度:退化维度通常是业务中一些简单、稳定的标识符,它们不会频繁变化,通常只是一个值(如编号、ID等),没有更多的属性或层级结构。
退化维度与维度表的区别:
- 维度表:通常包含一个主键字段,以及与业务相关的多个属性(如“产品维度表”可能包括产品编号、产品名称、产品类别等属性)。维度表是独立的,通常是星型模式(Star Schema)或雪花型模式(Snowflake Schema)的一部分。
- 退化维度:没有独立的维度表,它通常只是事实表中的一个字段,用于标识某个业务过程,但没有额外的属性或描述。
2.3.6 非规范化扁平维度
非规范化扁平维度是通过将多个维度表合并为一个扁平表(多个维度表合并为一个大表)来提高查询性能,减少联接操作,简化查询,但同时也带来数据冗余和更新维护上的问题
在这种设计中,数据不按规范化的方式进行存储,而是以扁平的结构存储在一个维度表中🤔。
其主要目的是减少复杂的表连接,提供更高效的查询性能,特别是在OLAP查询(联机分析处理)中。
- 非规范化扁平维度的特点🤨
- 数据冗余:为了提高查询性能,多个属性会被合并到一个表中,因此会导致数据冗余。例如,一个表中可能包含多个不同维度的属性,如产品、客户、地区等,而这些维度在规范化设计中通常会分布在不同的维度表中。
- 减少联接操作:通过将多个维度合并为一个扁平维度表,查询时不需要对多个维度表进行连接操作,这在查询过程中能够节省大量的时间和计算资源。
- 简化查询:查询时不需要复杂的联接,直接从一个表中提取所有相关信息,通常适用于需要频繁分析和聚合的场景。
- 存储空间:由于数据冗余和扁平化存储,非规范化扁平维度表通常会占用更多的存储空间。
- 非规范化与规范化的对比
-
规范化设计:规范化设计的目标是消除数据冗余,将数据分割成多个表,并通过主键/外键关系来连接。这样可以减少存储空间并避免数据冗余,但查询时需要对多个表进行联接,可能导致查询效率较低。
-
非规范化设计:非规范化设计通过将多个相关的属性和维度放在一个表中,避免了复杂的联接操作。这种方法通常会导致数据冗余,但查询速度较快,因为数据已经被“预处理”并且存储为一个扁平化的结构。
Demo:
规范化设计:
-
产品维度表(Product Dimension):
Product_ID Product_Name Category 1 手机 电子产品 2 衣服 服装 -
客户维度表(Customer Dimension):
Customer_ID Customer_Name Customer_Segment 101 张三 VIP 102 李四 普通 -
地区维度表(Region Dimension):
Region_ID Region_Name 1 北京 2 上海 -
销售事实表(Sales Fact):
Sales_ID Product_ID Customer_ID Region_ID Amount 1 1 101 1 1000 2 2 102 2 500
非规范化扁平维度设计:
- 销售维度表(Flattened Sales Dimension):
Sales_ID Product_ID Product_Name Category Customer_ID Customer_Name Customer_Segment Region_ID Region_Name Amount 1 1 手机 电子产品 101 张三 VIP 1 北京 1000 2 2 衣服 服装 102 李四 普通 2 上海 500
销售维度表中包含了所有维度的字段:产品名称、产品类别、客户姓名、客户细分、地区名称等。
非规范化扁平维度设计在查询时不需要对不同的维度表进行联接,直接通过一个扁平的表进行分析。
2.3.7 多层次维度
多层次维度(Hierarchical Dimension)是指的是在维度中存在层次结构,每个层次代表不同的聚合级别。
通过多层次维度,用户可以根据需要从较高层次的数据下钻(drill-down)到更详细的层次,或者从较低层次的数据上卷(drill-up)到更高层次的汇总数据。
Demo:
时间维度(Time Dimension)
时间_ID | 年 | 季度 | 月 | 周 | 日 |
---|---|---|---|---|---|
1 | 2024 | Q1 | 1 | 1 | 2024-01-01 |
2 | 2024 | Q1 | 1 | 2 | 2024-01-02 |
3 | 2024 | Q1 | 1 | 3 | 2024-01-03 |
4 | 2024 | Q1 | 2 | 4 | 2024-02-01 |
5 | 2024 | Q2 | 4 | 12 | 2024-04-01 |
6 | 2024 | Q2 | 5 | 13 | 2024-05-01 |
在这个表中,年、季度、月、周和日形成了多层次结构。可以按不同层级进行下钻或上卷:
- 按年:用户可以先看到汇总的年度数据(例如,2024年的总销售额)。
- 按季度:再按季度深入(例如,Q1的销售额)。
- 按月:进一步查看每个月的数据(例如,2024年1月的销售额)。
- 按日:可以查看具体某一天的数据(例如,2024年1月1日的销售额)。
地理维度(Geography Dimension)
地理_ID | 国家 | 省/市 | 城市 | 区域 |
---|---|---|---|---|
1 | 中国 | 北京市 | 北京市 | 朝阳区 |
2 | 中国 | 上海市 | 上海市 | 徐汇区 |
3 | 美国 | 加利福尼亚州 | 洛杉矶 | 市中心区 |
4 | 美国 | 纽约州 | 纽约市 | 曼哈顿区 |
层次结构包括国家、省/市、城市和区域。可以从“国家”开始查看汇总数据,逐步下钻到具体的城市或区域。
2.3.8 文档属性的标识与指示器
文档属性的标识与指示器是用于描述和管理文档的特性、状态和行为的关键元素。
标识符(ID)确保文档的唯一性,而指示器反映文档的状态、权限或任务要求。
Demo:
文档管理系统中,关于公司年度财务报告的文档。文档的属性可能包括:
- 文档ID:
Doc2024_FinancialReport
- 文档名称:
2024年财务报告
- 文档类型:
财务报告
- 创建日期:
2024-01-01
- 修改日期:
2024-03-01
- 版本号:
v1.1
- 作者:
yushifu
系统还可以有以下指示器来表示文档的状态:
- 审核指示器:
✔
表示文档已通过审核。 - 归档指示器:
未归档
,表示文档还没有归档。 - 权限指示器:
仅限财务部门
,表示只有财务部门人员可以访问此文档。
文档ID确保每个报告都是唯一的,审核指示器告诉用户文档是否已经审核通过,权限指示器则明确哪些用户可以访问这个文档。🤣🤣🤣
2.3.9 维度表中的空值属性
推荐采用描述性字符串替代空值,避免使用空值(NULL)的做法。
空值处理的不一致性
不同的数据库管理系统(DBMS)在处理空值时的行为可能不同,这会导致跨系统、跨平台的兼容性问题。特别是在进行分组、连接、聚合、排序等操作时,空值可能会被不同的数据库系统以不同的方式处理。
- 分组:在某些数据库中,空值可能会被视为一个单独的组,而在其他数据库中,空值可能会被忽略或与其他值合并。
- 聚合函数:某些聚合函数(如
COUNT
、SUM
等)在遇到空值时的行为不同。例如,某些数据库会将空值排除在外,而其他数据库则会将其计为零。 - 连接操作:在进行表连接时,空值可能导致不同的连接行为。使用空值时,联接条件的匹配可能不按预期工作,影响查询结果。
Demo:
某些员工的“部门”字段为空(NULL),可以使用“未知部门”来替代空值:
员工ID | 员工姓名 | 部门 |
---|---|---|
1 | 张三 | 销售部 |
2 | 李四 | 技术部 |
3 | 王五 | 未知部门 |
在查询时,无论使用哪个数据库系统,"未知部门"
都会被视为一个有效的字符串,参与分组、聚合和排序等操作,而不会因为空值的特殊处理导致不一致。
数据质量和业务逻辑
空值通常表示数据缺失或未定义,这在某些情况下可能是不可避免的。然而,过多的空值会导致数据质量问题和分析困难。采用描述性字符串替代空值,可以更明确地标识数据的缺失或异常,进而帮助维护数据的质量和一致性。
例如,当某个数据字段为空时,使用描述性字符串(如“待定”、“数据缺失”)可以明确表示该数据尚未确定或缺失,而不是简单的空值,避免了不确定性的困扰。
便于报告和展示
在生成报告和数据可视化时,空值可能会导致显示不完整或不易理解的结果。使用描述性字符串(如“无数据”、“待定”等)可以确保报告更加清晰易懂,避免了空值带来的空白或无意义的显示。
例如,当报表中出现空值时,用户可能无法理解该字段的实际含义,而用描述性字符串替代空值可以提供更多上下文信息,使报表更加直观和易于解读。
2.3.10 日历日期维度
日历日期维度(Calendar Date Dimension)通常用于描述与时间相关的各类信息。
Demo:
- 日期ID(Date Key):每个日期的唯一标识符,通常是一个整型或字符型的字段,格式可以是
YYYYMMDD
(例如20241216
)。 - 日期(Date):实际的日期字段,通常是
DATE
类型,表示某一天。 - 年(Year):日期所属的年份。
- 季度(Quarter):日期所属的季度(通常是1, 2, 3, 4)。
- 月份(Month):日期所属的月份(1到12)。
- 月名称(Month Name):月份的名称,如
January
、February
等。 - 周数(Week Number):日期所属的周次(通常是1到52)。
- 周末标识(Weekend Flag):标识某一天是否为周末。
- 工作日标识(Weekday Flag):标识某一天是否为工作日。
- 周几(Day of Week):表示日期是星期几(1到7,或者星期一到星期天)。
- 日(Day of Month):日期是一个月中的第几天(1到31)。
- 是否节假日(Holiday Flag):标识日期是否为节假日。
- 是否上半年(First Half of Year Flag):标识日期是否为上半年(1表示上半年,0表示下半年)。
- 季节(Season):日期所属的季节(如春、夏、秋、冬)。
设计原则
- 唯一性:每一行代表一个日期,日期ID应确保唯一。
- 灵活性:需要设计多个字段来支持按不同粒度进行时间分析。
- 扩展性:日历维度应支持扩展,能够方便地处理未来的日期,避免在将来需要重新生成日期维度。
- 考虑假期:如果业务涉及假期分析,应考虑在日期维度中加入假期字段。
日期ID | 日期 | 年 | 季度 | 月 | 月名称 | 周数 | 周几 | 日 | 工作日标识 | 是否节假日 |
---|---|---|---|---|---|---|---|---|---|---|
20240101 | 2024-01-01 | 2024 | 1 | 1 | January | 1 | 1 | 1 | 0 | 1 |
20240102 | 2024-01-02 | 2024 | 1 | 1 | January | 1 | 2 | 2 | 1 | 0 |
20240103 | 2024-01-03 | 2024 | 1 | 1 | January | 1 | 3 | 3 | 1 | 0 |
20240104 | 2024-01-04 | 2024 | 1 | 1 | January | 1 | 4 | 4 | 1 | 0 |
20240105 | 2024-01-05 | 2024 | 1 | 1 | January | 1 | 5 | 5 | 1 | 0 |
20240106 | 2024-01-06 | 2024 | 1 | 1 | January | 1 | 6 | 6 | 0 | 1 |
生成日历日期维度表通常有两种方式:
静态生成法
静态生成法适用于历史数据已经确定且维度的时间范围有限的情况。可以根据需要的日期范围(例如从2000年到2025年),手动或通过脚本生成日期维度表。该方式通常适合在小规模的业务中。
动态生成法
动态生成法适用于业务需求变化较快或维度表数据需要持续更新的情况。例如,使用ETL工具或SQL脚本动态生成,实时生成未来的日期维度,并支持自动更新。动态生成的日期维度表能够根据实际业务需求灵活调整。
2.3.11 扮演角色的维度
扮演角色的维度(Role-Playing Dimension)指的是同一维度表根据业务需求在不同的上下文中“扮演”不同角色的情况。这种设计模式主要用于处理同一维度在不同场景下的多次引用。
- 客户作为下单者:在订单事实表中,客户可能作为“下单者”角色存在。此时,客户ID会作为外键关联到客户维度表,以便获取下单者的详细信息。
- 客户作为收货人:在相同的订单事实表中,客户也可能作为“收货人”角色存在。此时,同样是客户维度,但由于角色不同,可能需要通过不同的外键(如
Customer_ID
和Receiver_ID
)来区分。
处理方法
1 在事实表中使用多个外键
事实表中可以通过多个外键来引用同一个维度表。每个外键代表不同的角色,例如“下单者”和“收货人”都使用Customer_ID
字段,但它们的业务角色不同。这样可以避免维度表冗余。
2 为不同角色命名维度表
如果同一个维度表有多个角色并且角色之间有显著差异,可以考虑为每个角色创建不同的维度表,这样可以更加明确和简化查询。不过,这种方法可能会带来一些冗余,通常适用于角色差异较大的情况。
- 下单客户维度(Order Customer Dimension)
- 收货客户维度(Shipping Customer Dimension)
2.3.12 杂项维度
杂项维度(Junk Dimension)用于存储一些不属于任何主维度(如客户、时间、产品等)的低维度属性。这些属性通常不具备明显的业务含义,也不适合单独建立维度表,但它们对于业务分析和查询有一定的作用。
-
减少维度表数量:一些低维度的属性如果每个都单独创建一个维度表,会导致维度表的数量过多,从而增加数据库的复杂性和维护成本。通过将它们放入一个杂项维度表,可以显著减少维度表的数量。
-
简化数据模型:将多个不相关的低卡数字段合并成一个维度表,可以使数据模型更加简洁,避免冗余和不必要的复杂度。
- 提高查询性能:由于这些字段通常是低卡数的(例如只有几个可能的值),将它们放入一个杂项维度表中,可以通过减少维度表的关联来提高查询性能。
- 避免数据冗余:避免在多个事实表中重复存储这些独立的小字段,从而减少数据冗余。
常见的杂项维度字段
- 状态标志:表示某个实体的状态,如“是否有效”、“是否已激活”等。
- 类型标志:如“销售类型”、“订单类型”等。
- 优先级:如“高优先级”、“低优先级”等。
- 分类标签:如“客户分类”、“产品标签”等。
- 小型代码:表示一些小的分类代码,如“支付方式”、“配送方式”等。
这些字段通常是用来为事实表提供额外的上下文信息的,但它们没有足够的业务含义来单独创建维度表。
Demo🤣🤣🤣:
杂项维度ID | 状态标志 | 优先级 | 支付方式 | 订单类型 |
---|---|---|---|---|
1 | 启用 | 高 | 信用卡 | 在线 |
2 | 启用 | 低 | 支付宝 | 离线 |
3 | 禁用 | 高 | 微信支付 | 在线 |
4 | 启用 | 中 | 信用卡 | 离线 |
- 杂项维度ID:唯一标识符,用作其他表的外键。
- 状态标志、优先级、支付方式、订单类型:这些是低卡数的小属性,通过杂项维度ID将它们组合成一个记录。
订单ID | 客户ID | 销售金额 | 杂项维度ID |
---|---|---|---|
1001 | C001 | 500 | 1 |
1002 | C002 | 200 | 2 |
1003 | C003 | 150 | 3 |
通过 杂项维度ID
外键,可以查到该订单的状态、优先级、支付方式和订单类型,而不需要在事实表中重复存储这些字段。
何时使用杂项维度
- 多个低卡数属性:当一个事实表或维度表中有多个小属性,它们可能没有单独的业务含义,且数量有限。
- 避免冗余:当这些小属性是重复的且频繁出现时,使用杂项维度表可以避免在事实表中冗余存储它们。
- 简化数据模型:当这些小属性的独立性较弱且没有独立业务需求时,使用杂项维度表可以简化数据模型和减少表的数量。
2.3.13 雪花维度
雪花维度(Snowflake Dimension)是一种数据仓库设计模式,它是星型模式(Star Schema)的一种变体。
在雪花模型中,维度表被进一步规范化(Normalized),即将原本可以放在一个维度表中的多个字段分解成多个相关的子维度表。
相比星型模型中维度表的“扁平”结构,雪花模型的维度表具有更多的层次关系,形成类似雪花形状的结构,因此得名“雪花维度”。
- 规范化:雪花维度通过规范化的方式,将维度表中的字段分解成多个子表,减少了数据的冗余。例如,在产品维度表中,如果有产品类别和产品品牌字段,可能会将这两个字段分别抽象成独立的“产品类别”维度和“产品品牌”维度。
- 多层级关系:雪花维度的结构通常包含多个层次。例如,产品维度可能有“产品类别” → “产品品牌” → “产品名称”这样的层次结构,这样可以更灵活地进行数据管理。
- 复杂的查询:雪花模型的查询通常比星型模型更复杂,因为它需要多表连接来获取完整的维度信息。
Demo🤣🤣🤣:
星型模型中的产品维度
产品ID | 产品名称 | 品牌 | 类别 |
---|---|---|---|
P001 | 手机 | 苹果 | 电子产品 |
P002 | 洗衣机 | 海尔 | 家电 |
P003 | 电视机 | 索尼 | 家电 |
雪花模型中的产品维度
在雪花模型中,产品维度表被进一步规范化,拆分成多个子表。
- 产品维度表:
产品ID | 产品名称 | 品牌ID | 类别ID |
---|---|---|---|
P001 | 手机 | B001 | C001 |
P002 | 洗衣机 | B002 | C002 |
P003 | 电视机 | B003 | C002 |
- 品牌维度表:
品牌ID | 品牌名称 |
---|---|
B001 | 苹果 |
B002 | 海尔 |
B003 | 索尼 |
- 类别维度表:
类别ID | 类别名称 |
---|---|
C001 | 电子产品 |
C002 | 家电 |
- 减少数据冗余:通过规范化,雪花模型避免了数据的重复存储。例如,品牌和类别信息被提取到单独的表中,避免了每个产品记录中都存储品牌和类别信息。
- 数据更新方便:因为数据冗余较少,如果品牌或类别信息发生变化,只需要在相应的子维度表中进行修改,不需要修改每一条产品记录。
- 易于管理:规范化后的表更符合标准化的数据库设计原则,结构更加清晰,数据管理和维护更加规范。
特性 | 星型维度 | 雪花维度 |
---|---|---|
结构 | 扁平化,所有维度字段都集中在一个维度表中 | 规范化,维度表拆分成多个子维度表 |
查询性能 | 查询速度较快,因为维度表不需要连接 | 查询性能较差,需要多表JOIN操作 |
数据冗余 | 可能存在冗余数据,因为重复存储相同的信息 | 数据冗余少,减少了数据存储量 |
维护复杂度 | 维护相对简单,因为只有一个维度表 | 维护相对复杂,因为涉及多个维度表 |
ETL过程复杂度 | ETL过程较简单,数据直接插入维度表 | ETL过程复杂,需要分解并规范化数据 |
何时使用雪花维度
- 数据的规范化需求:如果数据仓库中需要减少数据冗余并使数据更加规范化,雪花模型是一个好的选择。例如,产品的品牌和类别信息经常被重复使用,拆分成子表可以减少冗余。
- 维度变化不频繁:当维度表中的字段变化不频繁时,使用雪花模型会让数据管理更加清晰,同时降低存储空间。
- 查询负载较低或查询需求不复杂:如果查询性能不是最关键的因素,或者查询的维度表相对较小,雪花模型可以提供较好的数据结构和管理。
2.3.14 支架维度
支架维度(Bridge Dimension)是一种特殊类型的维度表,用于处理多对多关系的情况,尤其是在事实表和维度表之间存在复杂的多对多映射时。
支架维度的主要作用是解决在一个事实记录中需要关联多个维度值的场景,常见的应用场景包括多个角色、多个产品类别、多项业务标志等。
在某些情况下用来桥接两个维度表,使得每条事实记录能够同时关联多个维度值。支架维度的主要作用是将多个维度值组合在一起,作为一个联合维度,帮助简化多对多关系的处理。
Demo:
- 员工维度:
员工ID | 员工姓名 |
---|---|
E001 | 张三 |
E002 | 李四 |
E003 | 王五 |
- 角色维度:
角色ID | 角色名称 |
---|---|
R001 | 销售代表 |
R002 | 客户经理 |
- 支架维度表(桥接表):
支架维度ID | 员工ID | 角色ID |
---|---|---|
1 | E001 | R001 |
1 | E002 | R002 |
2 | E003 | R001 |
- 产品维度:
产品ID | 产品名称 |
---|---|
P001 | 手机 |
P002 | 电视机 |
P003 | 洗衣机 |
- 供应商维度:
供应商ID | 供应商名称 |
---|---|
S001 | 苹果公司 |
S002 | 三星公司 |
S003 | 海尔公司 |
- 支架维度表:
支架维度ID | 产品ID | 供应商ID |
---|---|---|
1 | P001 | S001 |
1 | P001 | S002 |
2 | P002 | S003 |
支架维度的优点
-
简化多对多关系:支架维度可以帮助解决事实表和维度表之间的多对多关系,避免了将多个维度值重复存储在事实表中的冗余数据。
-
提高查询灵活性:支架维度可以灵活地关联多个维度,使得查询更具灵活性。通过支架维度表,可以在多个维度之间进行更复杂的分析。
支架维度的缺点
- 查询复杂性:支架维度的使用增加了查询的复杂性,因为查询时需要多表连接。如果查询涉及多个支架维度,可能需要做大量的联接操作。
- ETL过程复杂:在ETL过程中,需要将多个维度表中的数据组合到支架维度表中,这可能增加ETL过程的复杂性和计算成本。