目录
本篇首先介绍关系数据模型、多维数据模型和Data Vault模型这三种常见的数据仓库模型和与之相关的设计方法,然后讨论数据集市的设计问题,最后说明一个数据仓库项目的实施步骤。规划实施过程是整个数据仓库设计的重要组成部分。
关系模型、多维模型已经有很长的历史,而Data Vault模型相对比较新。它们都是流行的数据仓库建模方式,但又有各自的特点和适用场景。读者在了解了本篇的内容后,可以根据实际需求选择适合的方法构建自己的数据仓库。
2.1 关系数据模型
关系模型是由E.F.Codd在1970年提出的一种通用数据模型。由于关系数据模型简单明了,并且有坚实的数学理论基础,所以一经推出就受到了业界的高度重视。关系模型被广泛应用于数据处理和数据存储,尤其是在数据库领域,现在主流的数据库管理系统几乎都是以关系数据模型为基础实现的。
2.1.1 关系数据模型中的结构
关系数据模型基于关系这一数学概念。在本小节中,解释关系数据模型中的术语和相关概念。为了便于说明,我们使用一个分公司-员工关系的例子。假设有一个大型公司在全国都有分公司,每个员工属于一个分公司,一个分公司有一个经理,分公司经理也是公司员工。分公司-员工关系如图2-1所示。
图2-1 分公司-员工关系
关系
由行和列构成的二维结构,对应关系数据库中的表,如示例中的分公司表和员工表。注意,这种认识只是我们从逻辑上看待关系模型的方式,并不应用于表在磁盘上的物理结构。表的物理存储结构可以是堆文件、索引文件或哈希文件。堆文件是一个无序的数据集合,索引文件中表数据的物理存储顺序和逻辑顺序保持一致,哈希文也称为直接存取文件,是通过一个预先定义好的哈希函数确定数据的物理存储位置。
属性
由属性名称和类型名称构成的顺序对,对应关系数据库中表的列,如地址(Variable Characters)是公司表的一个属性。属性值是属性一个特定的有效值,可以是简单的标量值,也可以是复合数据类型值。
在关系数据模型中,我们把关系描述为表,表中的行对应不同的记录,表中的列对应不同的属性。属性可以以任何顺序出现,而关系保持不变,也就是说,在关系理论中,表中的列是没有顺序的。
属性域
属性的取值范围。每一个属性都有一个预定义的值的范围。属性域是关系模型的一个重要特征,关系中的每个属性都与一个域相关。各个属性的域可能不同,也可能相同。域描述了属性所有可能的值。
域的概念是很重要的,因为它允许我们定义属性可以具有的值的意义。系统可因此获得更多的信息,并且可以拒绝不合理的操作。在我们的例子中,分公司编号和员工编号都是字符串,但显然具有不同的含义,换句话说,它们的属性域是不同的。表2-1列出了分公司-员工关系的一些属性域。
属性 | 属性域的定义 | 含义 |
分公司编号 | 字符:大小为4,范围为B001-B999 | 设置所有可能的分公司编号 |
地址 | 字符:大小为100 | 设置所有可能的地址 |
员工编号 | 字符:大小为5,范围为S0001-S9999 | 设置所有可能的员工编号 |
职位类别 | 管理、技术、销售、运营、产品之一 | 设置所有可能的员工职位类别 |
表2-1 分公司-员工关系的一些属性域
元组
关系中的一条记录,对应关系数据库中的一个表行。元组可以以任何顺序出现,而关系保持不变,也就是说,在关系理论中,表中的行是没有顺序的。
关系数据库
一系列规范化的表的集合。这里的规范化可以理解为表结构的正确性。本节后面会详细讨论规范化问题。
以上介绍了关系数据模型的两组术语:“关系、属性、元组”和“表、列、行”。在这里它们的含义是相同的,只不过前者是关系数据模型的正式术语,而后者是常用的数据库术语。其它可能会遇到的类似术语还有实体(表)、记录(行)、字段(列)等。
关系表的属性
关系表有如下属性:
- 每个表都有唯一的名称。
- 一个表中每个列有不同的名字。
- 一个列的值来自于相同的属性域。
- 列是无序的。
- 行是无序的。
关系数据模型中的键
超键
一个列或者列集,唯一标识表中的一条记录。超键可能包含用于唯一标识记录所不必要的额外的列,我们通常只对仅包含能够唯一标识记录的最小数量的列感兴趣。
候选键
仅包含唯一标识记录所必须的最小数量列的超键。表的候选键有三个属性:
- 唯一性:在每条记录中,候选键的值唯一标识该记录。
- 最小性:具有唯一性属性的超键的最小子集。
- 非空性:候选键的值不允许为空。
在我们的例子中,分公司编号是候选键,如果每个分公司的邮编都不同,那么邮编也可以作为分公司表的候选键。一个表中允许有多个候选键。
主键
唯一标识表中记录的候选键。主键是唯一、非空的。没有被选做主键的候选键称为备用键。对于例子中的分公司表,分公司编号是主键,邮编就是备用键,而员工表的主键是员工编号。
主键的选择在关系数据模型中非常重要,很多性能问题都是由于主键选择不当引起的。在选择主键时,我们可以参考以下原则:
- 主键要尽可能的小。
- 主键值不应该被改变。主键会被其它表所引用。如果改变了主键的值,所有引用该主键的值都需要修改,否则引用就是无效的。
- 主键通常使用数字类型。数字类型的主键要比其它数据类型效率更高。
- 主键应该是没有业务含义的,它不应包含实际的业务信息。无意义的数字列不需要修改,因此是主键的理想选择。大部分关系型数据库支持的自增属性或序列对象更适合当做主键。
- 虽然主键允许由多列组成,但应该使用尽可能少的列,最好是单列。
外键
一个表中的一列或多列的集合,这些列匹配某些其它(也可以是同一个)表中的候选键。注意外键所引用的不一定是主键,但一定是候选键。当一列出现在两张表中的时候,它通常代表两张表记录之间的关系。如例子中分公司表的分公司编号和员工表的所属分公司。它们的名字虽然不同,但却是同一含义。分公司表的分公司编号是主键,在员工表里所属分公司是外键。同样,因为公司经理也是公司员工,所以它是引用员工表的外键。主键所在的表被称为父表,外键所在的表被称为子表。
2.1.2 关系完整性
上一小节讨论了关系数据模型的结构部分,本小节讨论关系完整性规则。关系数据模型有两个重要的完整性规则:实体完整性和参照完整性。在定义这些术语之前,先要理解空值的概念。
空值(NULL)
表示一个列的值目前还不知道或者对于当前记录来说不可用。空值可以意味着未知,也可以意味着某个记录没有值,或者只是意味着该值还没有提供。空值是处理不完整数据或异常数据的一种方式。空值与数字零或者空字符串不同,零和空字符串是值,但空值代表没有值。因此,空值应该与其它值区别对待。空值具有特殊性,当它参与逻辑运算时,结果取决于真值表。每种数据库系统对空值参与运算的规则定义也不尽相同。表2-2到表2-4分别为大部分主流数据库系统(Oracle、MySQL、PostgreSQL、Greenplum等)的非、与、或逻辑运算真值表。
TRUE | FALSE | NULL | |
NOT | FALSE | TRUE | NULL |
表2-2 逻辑非运算
AND | TRUE | FALSE | NULL |
TRUE | TRUE | FALSE | NULL |
FALSE | FALSE | FALSE | FALSE |
NULL | NULL | FALSE | NULL |
表2-3 逻辑与运算
OR | TRUE | FALSE | NULL |
TRUE | TRUE | TRUE | TRUE |
FALSE | TRUE | FALSE | NULL |
NULL | TRUE | NULL | NULL |
表2-4 逻辑或运算
在我们的例子中,如果一个分公司的经理离职了,新的经理还没有上任,此时公司经理列对应的值就是空值。有了空值的定义,就可以定义两种关系完整性规则了。
实体完整性
在一个基本表中,主键列的取值不能为空。基本表指的是命名的表,其中的记录物理地存储在数据库中,与之对应的是视图。视图是虚拟的表,它只是一个查询语句的逻辑定义,其中并没有物理存储数据。
从前面介绍的定义可知,主键是用于唯一标识记录的最小列集合。也就是说,主键的任何子集都不能提供记录的唯一标识。空值代表未知,无法进行比较。如果允许空值作为主键的一部分,就意味着并不是所有的列都用来区分记录,这与主键的定义矛盾,因此主键必须是非空的。例如,分公司编号是分公司表的主键,在录入数据的时候,该列的值不能为空。
参照完整性
如果表中存在外键,则外键值必须与主表中的某些记录的候选键值相同,或者外键的值必须全部为空。在图2-1中,员工表中的所属分公司是外键。该列的值要么是分公司表的分公司编号列中的值,要么是空(如新员工已经加入了公司,但还没有被分派到某个具体的分公司时)。
业务规则
定义或约束组织的某些方面的规则。业务规则的例子包括属性域和关系完整性规则。属性域用于约束特定列能够取的值。大部分主流数据库系统(Oracle、MySQL、PostgreSQL、Greenplum等)支持叫做check的约束,也用于定义列中可以接受的值,但这种约束是定义在属性域之上的,比属性域的约束性更强。例如,员工表的性别列就可以加上check约束,使它只能取有限的几个值。
2.1.3 关系数据库语言
关系语言定义了允许对数据进行的操作,包括从数据库中更新或检索数据所用的操作以及改变数据库对象结构的操作。关系数据库的主要语言是SQL语言。
SQL是Structured Query Language的缩写,意为结构化查询语言。SQL已经被国际标准化组织(ISO)进行了标准化,使它成为正式的和事实上的定义和操纵关系数据库的标准语言。SQL语言又可分为DDL、DML、DCL、TCL四类。
DDL是Data Definition Language的缩写,意为数据定义语言,用于定义数据库结构和模式。典型的DDL有create、alter、drop、truncate、comment、rename等。
DML是Data Manipulation Language的缩写,意为数据操纵语言,用于检索、管理和维护数据库对象。典型的DML有select、insert、update、delete、merge、call、explain、lock等。
DCL是Data Control Language的缩写,意为数据控制语言,用于授予和回收数据库对象上的权限。典型的DCL有grant和revoke。
TCL是Transaction Control Language的缩写,意为事务控制语言,用于管理DML对数据的改变。它允许一组DML语句联合成一个逻辑事务。典型的TCL有commit、rollback、savepoint、set transaction等。
2.1.4 规范化
关系数据模型的规范化是一种组织数据的技术。规范化方法对表进行分解,以消除数据冗余,避免异常更新,提高数据完整性。
不规范化带来的问题
没有规范化,数据的更新处理将变得困难,异常的插入、修改、删除数据的操作会频繁发生。为了便于理解,来看下面的例子。
假设有一个名为employee的员工表,它有九个属性:id员工编号,name员工姓名,mobile电话,zip邮编,province省份,city城市,district区县,deptNo所属部门编号,deptName所属部门名称,表中的数据如表2-5所示。
id | Name | Mobile | zip | province | city | district | deptNo | deptName |
101 | 张三 | 13910000001 13910000002 | 100001 | 北京 | 北京 | 海淀区 | D1 | 部门1 |
101 | 张三 | 13910000001 13910000002 | 100001 | 北京 | 北京 | 海淀区 | D2 | 部门2 |
102 | 李四 | 13910000003 | 200001 | 上海 | 上海 | 静安区 | D3 | 部门3 |
103 | 王五 | 13910000004 | 510001 | 广东省 | 广州 | 白云区 | D4 | 部门4 |
103 | 王五 | 13910000004 | 510001 | 广东省 | 广州 | 白云区 | D5 | 部门5 |
表2-5 非规范化的员工表
由于此员工表是非规范化的,我们将面对如下的问题。
- 修改异常:上表中张三有两条记录,因为他隶属两个部门。如果我们要修改张三的地址,必须修改两行记录。假如一个部门得到了张三的新地址并进行了更新,而另一个部门没有,那么此时张三在表中会存在两个不同的地址,导致了数据不一致。
- 新增异常:假如一个新员工加入公司,他正处于入职培训阶段,还没有被正式分配到某个部门,如果deptNo字段不允许为空,我们就无法向employee表中新增该员工的数据。
- 删除异常:假设公司撤销了D3这个部门,那么在删除deptNo为D3的行时,会将李四的信息也一并删除。因为他只隶属于D3这一个部门。
为了克服这些异常更新,我们需要对表进行规范化设计。规范化是通过应用范式规则实现的。最常用的范式有第一范式(1NF)、第二范式(2NF)、第三范式(3NF)。
第一范式(1NF)
表中的列只能含有原子性(不可再分)的值。
上例中张三有两个手机号存储在mobile列中,违反了1NF规则。为了使表满足1NF,数据应该修改为如表2-6所示。
id | name | mobile | zip | province | city | district | deptNo | deptName |
101 | 张三 | 13910000001 | 100001 | 北京 | 北京 | 海淀区 | D1 | 部门1 |
101 | 张三 | 13910000002 | 100001 | 北京 | 北京 | 海淀区 | D1 | 部门1 |
101 | 张三 | 13910000001 | 100001 | 北京 | 北京 | 海淀区 | D2 | 部门2 |
101 | 张三 | 13910000002 | 100001 | 北京 | 北京 | 海淀区 | D2 | 部门2 |
102 | 李四 | 13910000003 | 200001 | 上海 | 上海 | 静安区 | D3 | 部门3 |
103 | 王五 | 13910000004 | 510001 | 广东省 | 广州 | 白云区 | D4 | 部门4 |
103 | 王五 | 13910000004 | 510001 | 广东省 | 广州 | 白云区 | D5 | 部门5 |
表2-6 满足1NF的员工表
第二范式(2NF)
第二范式要同时满足下面两个条件:满足第一范式;没有部分依赖。例如,员工表的一个候选键是{id,mobile,deptNo},而deptName依赖于{deptNo},同样name仅依赖于{id},因此不是2NF的。为了满足第二范式的条件,需要将这个表拆分成employee、dept、employee_dept、employee_mobile四个表,如表2-7至表2-10所示。
id | name | zip | province | city | District |
101 | 张三 | 100001 | 北京 | 北京 | 海淀区 |
102 | 李四 | 200001 | 上海 | 上海 | 静安区 |
103 | 王五 | 510001 | 广东省 | 广州 | 白云区 |
表2-7 满足2NF的员工表
deptNo | deptName |
D1 | 部门1 |
D2 | 部门2 |
D3 | 部门3 |
D4 | 部门4 |
D5 | 部门5 |
表2-8 满足2NF的部门表
id | deptNo |
101 | D1 |
101 | D2 |
102 | D3 |
103 | D4 |
103 | D5 |
表2-9 满足2NF的员工-部门表
id | mobile |
101 | 13910000001 |
101 | 13910000002 |
102 | 13910000003 |
103 | 13910000004 |
表2-10 满足2NF的员工-电话表
第三范式(3NF)
第三范式要同时满足下面两个条件:满足第二范式;没有传递依赖。例如,员工表的province、city、district依赖于zip,而zip依赖于{id},换句话说,province、city、district传递依赖于{id},违反了3NF规则。为了满足第三范式的条件,可以将这个表拆分成employee和zip两个表,如表2-11、表2-12所示。
id | name | zip |
101 | 张三 | 100001 |
102 | 李四 | 200001 |
103 | 王五 | 510001 |
表2-11 满足3NF的员工表
zip | province | City | District |
100001 | 北京 | 北京 | 海淀区 |
200001 | 上海 | 上海 | 静安区 |
510001 | 广东省 | 广州 | 白云区 |
表2-12 满足3NF的地区表
在关系数据模型设计中,一般需要满足第三范式的要求。如果一个表有良好的主外键设计,就应该是满足3NF的表。规范化带来的好处是通过减少数据冗余提高更新数据的效率,同时保证数据完整性。然而,我们在实际应用中也要防止过度规范化的问题。规范化程度越高,划分的表就越多,在查询数据时越有可能使用表连接操作。而如果连接的表过多,会影响查询的性能。关键的问题是要依据业务需求,仔细权衡数据查询和数据更新的关系,制定最适合的规范化程度。还有一点需要注意的是,不要为了遵循严格的规范化规则而修改业务需求。
2.1.5 关系数据模型与数据仓库
关系数据模型可以提供高性能的数据更新操作,能很好地满足事务型系统的需求,这点毫无疑问。但是对于查询与分析密集型的数据仓库系统还是否合适呢?对这个问题的争论由来已久,基本可以分为Inmon和Kimball两大阵营,Inmon阵营是应用关系数据模型构建数据仓库的支持者。
Inmon方法是以下面这些假设的成立为前提的。
- 假设数据仓库是以企业为中心的,初始的数据能够为所有部门所使用。而最终的数据分析能力是在部门级别体现,需要使用数据集市对数据仓库中的数据做进一步处理,以便为特定的部门定制它们。
- 数据仓库中的数据不违反组织制定的任何业务规则。
- 必须尽可能快地把新数据装载进数据仓库,这意味着需要简化数据装载过程或减少数据的装载量。
- 数据仓库的建立必须从一开始就被设计成支持多种BI技术,这就要求数据仓库本身所使用的技术越通用越好。
- 假设数据仓库的需求一定会发生变化。它必须能完美地适应其数据和数据结构的变化。
基于这些假设,使用关系数据模型构建数据仓库的优势和必然性就比较明显了。
非冗余性
为适应数据仓库有限的装载周期和海量数据,数据仓库数据模型应该包含最少量的数据冗余。冗余越少,需要装载的数据量就越少,装载过程就越快。另外,数据仓库的数据源一般是事务型系统,这些系统通常是规范化设计的。如果数据仓库使用相同的数据模型,意味着数据转换的复杂性可能会降低,同样可以加快数据装载速度。
稳定性
由于数据仓库的需求会不断变化,我们需要以一种迭代的方式建立数据仓库。众所周知,组织中最经常变化的是它的处理过程、应用和技术,如果依赖于这三个因素中的任何一个建立数据模型,当它们发生改变时,肯定要对数据模型进行彻底地修改。为了避免这个问题,关系数据模型的通用性正是用武之地。另一方面,由于变化不可避免,数据仓库模型应该能比较容易地将新的变化合并进来,而不必重新设计已有的元素和已经实现的实体。
一致性
数据仓库模型最本质的特点是保证作为组织最重要资源的数据的一致性。而确保数据一致性正是关系数据模型的特点之一。
灵活性
数据仓库最重要的一个用途是作为坚实的、可靠的、一致的数据基础为后续的报表系统、数据分析、数据挖掘或BI系统服务。数据模型还必须支持为组织建立的业务规则。这就意味着数据模型必须比简单的平面文件功能更强。为此关系数据模型也是最佳选择之一。
关系数据模型已被证明是可靠的、简单的数据建模方法。应用其规范化规则,将产生一个稳定的、一致的数据模型。该模型支持由组织制定的政策和约定的规则,同时为数据集市分析数据提供了更多的灵活性,结果数据库存储以及数据装载方面也是最有效的。
当然,任何一种数据模型都不可能是完美无瑕的。关系数据模型的缺点也很明显,它需要额外建立数据集市的存储区,并增加相应的数据装载过程。另外,对数据仓库的使用强烈依赖于对SQL语言的掌握程度。
2.2 维度数据模型
维度数据模型简称维度模型(Dimensional modeling,DM),是一套技术和概念的集合,用于数据仓库设计。不同于关系数据模型,维度模型不一定要引入关系数据库。在逻辑上相同的维度模型,可以被用于多种物理形式,比如维度数据库或是简单的平面文件。根据数据仓库大师Kimball的观点,维度模型是一种趋向于支持最终用户对数据仓库进行查询的设计技术,是围绕性能和易理解性构建的。尽管关系模型对于事务处理系统表现非常出色,但它并不是面向最终用户的。
事实和维度是两个维度模型中的核心概念。事实表示对业务数据的度量,而维度是观察数据的角度。事实通常是数字类型的,可以进行聚合和计算,而维度通常是一组层次关系或描述信息,用来定义事实。例如,销售金额是一个事实,而销售时间、销售的产品、购买的顾客、商店等等都是销售事实的维度。维度模型按照业务流程领域即主题域建立,例如进货、销售、库存、配送等。不同的主题域可能共享某些维度,为了提高数据操作的性能和数据一致性,需要使用一致性维度,例如几个主题域间共享维度的拷贝。术语“一致性维度”源自Kimball,指的是具有相同属性和内容的维度。
2.2.1 维度数据模型建模过程
维度模型通常以一种被称为星型模式的方式构建。所谓星型模式,就是以一个事实表为中心,周围环绕着多个维度表。还有一种模式叫做雪花模式,是对维度做进一步规范化后形成的。本节后面会讨论这两种模式。一般使用下面的过程构建维度模型:
- 选择业务流程
- 声明粒度
- 确认维度
- 确认事实
这种使用四步设计法建立维度模型的过程,有助于保证维度模型和数据仓库的可用性。
选择业务流程
确认哪些业务处理流程是数据仓库应该覆盖的,是维度方法的基础。因此,建模的第一个步骤是描述需要建模的业务流程。例如,需要了解和分析一个零售店的销售情况,那么与该零售店销售相关的所有业务流程都是需要关注的。为了描述业务流程,可以简单地使用纯文本将相关内容记录下来,或者使用“业务流程建模标注”(Business Process Modeling Notation,BPMN)方法,也可以使用统一建模语言(Unified Modeling Language,UML)或其它类似的方法。
声明粒度
确定了业务流程后,下一步是声明维度模型的粒度。这里的粒度用于确定事实中表示的是什么,例如,一个零售店的顾客在购物小票上的一个购买条目。在选择维度和事实前必须声明粒度,因为每个候选维度或事实必须与定义的粒度保持一致。在一个事实所对应的所有维度设计中强制实行粒度一致性是保证数据仓库应用性能和易用性的关键。从给定的业务流程获取数据时,原始粒度是最低级别的粒度。建议从原始粒度数据开始设计,因为原始记录能够满足无法预期的用户查询。汇总后的数据粒度对优化查询性能很重要,但这样的粒度往往不能满足对细节数据的查询需求。不同的事实可以有不同的粒度,但同一事实中不要混用多种不同的粒度。维度模型建立完成之后,还有可能因为获取了新的信息,而回到这步修改粒度级别。
确认维度
设计过程的第三步是确认模型的维度。维度的粒度必须和第二步所声明的粒度一致。维度表是事实表的基础,也说明了事实表的数据是从哪里采集来的。典型的维度都是名词,如日期、商店、库存等。维度表存储了某一维度的所有相关数据,例如,日期维度应该包括年、季度、月、周、日等数据。
确认事实
确认维度后,下一步是也是维度模型四步设计法的最后一步,就是确认事实。这一步识别数字化的度量,构成事实表的记录。它是和系统的业务用户密切相关的,因为用户正是通过对事实表的访问获取数据仓库存储的数据。大部分事实表的度量都是数字类型的,可累加,可计算,如成本、数量、金额等。
2.2.2 维度规范化
与关系模型类似,维度也可以进行规范化。对维度的规范化(又叫雪花化),可以去除冗余属性,是对非规范化维度做的规范化处理,在下面介绍雪花模型时,会看到维度规范化的例子。一个非规范化维度对应一个维度表,规范化后,一个维度会对应多个维度表,维度被严格地以子维度的形式连接在一起。实际上,在很多情况下,维度规范化后的结构等同于一个低范式级别的关系型结构。
设计维度数据模型时,会因为如下原因而不对维度做规范化处理:
- 规范化会增加表的数量,使结构更复杂。
- 不可避免的多表连接,使查询更复杂。
- 不适合使用位图索引。
- 查询性能原因。分析型查询需要聚合计算或检索很多维度值,此时第三范式的数据库会遭遇性能问题。如果需要的仅仅是操作型报表,可以使用第三范式,因为操作型系统的用户需要看到更细节的数据。
正如在前面关系模型中提到的,对于是否应该规范化的问题存在一些争论。总体来说,当多个维度共用某些通用的属性时,做规范化会是有益的。例如,客户和供应商都有省、市、区县、街道等地理位置的属性,此时分离出一个地区属性就比较合适。
2.2.3 维度数据模型的特点
- 易理解。相对于规范化的关系模型,维度模型容易理解且更直观。在维度模型中,信息按业务种类或维度进行分组,这会提高信息的可读性,也方便了对于数据含义的解释。简化的模型也让系统以更为高效的方式访问数据库。关系模型中,数据被分布到多个离散的实体中,对于一个简单的业务流程,可能需要很多表联合在一起才能表示。
- 高性能。维度模型更倾向于非规范化,因为这样可以优化查询的性能。介绍关系模型时多次提到,规范化的实质是减少数据冗余,以优化事务处理或数据更新的性能。这里用一个具体的例子进一步说明性能问题。如图2-2所示,左边是一个销售订单的典型的规范化表示。订单(Order)实体描述有关订单整体的信息,订单明细(Order Line)实体描述有关订单项的信息,两个实体都包含描述其订单状态的信息。右边是一个订单状态维(Order Status Dimension),该维描述订单和订单明细中对应的状态编码值的唯一组合。它包括在规范化设计的订单和订单明细实体中都出现的属性。当销售订单事实行被装载时,参照在订单状态维中的适合的状态编码的组合设置它的外键。
图2-2 销售订单规范化表与销售订单维度表
维度设计的整体观点是要简化和加速查询。假设有100万订单,每个订单有10条明细,订单状态和订单明细状态各有10种。如果用户要查询某种状态特性的订单,按3NF模型,逻辑上需要关联100万记录与1000万记录的两个大表,然后过滤两个表的状态值得到所要的结果。另一方面,事实表(图中并没有画出)按最细数据粒度有1000万记录,3NF里的订单表属性在事实表里是冗余数据,状态维度有100条数据,只需要关联1000万记录与100条记录的两个表,再进行状态过滤即可。
- 可扩展。维度模型是可扩展的。由于维度模型允许数据冗余,因此当向一个维度表或事实表中添加字段时,不会像关系模型那样产生巨大的影响,带来的结果就是更容易容纳不可预料的新增数据。这种新增可以是单纯地向表中增加新的数据行而不改变表结构,也可以是在现有表上增加新的属性。基于数据仓库的查询和应用不需要过多改变就能适应表结构的变化,老的查询和应用会继续工作而不会产生错误的结果。但是对于规范化的关系模型,由于表之间存在复杂的依赖关系,改变表结构前一定要仔细考虑。
2.2.4 星型模式
星型模式是维度模型最简单的形式,也是数据仓库以及数据集市开发中使用最广泛的形式。星型模式由事实表和维度表组成,一个星型模式中可以有一个或多个事实表,每个事实表引用任意数量的维度表。星型模式的物理模型像一颗星星的形状,中心是一个事实表,围绕在事实表周围的维度表表示星星的放射状分支,这就是星型模式这个名字的由来。
星型模式将业务流程分为事实和维度。事实包含业务的度量,是定量的数据,如销售价格、销售数量、距离、速度、重量等是事实。维度是对事实数据属性的描述,如日期、产品、客户、地理位置等是维度。一个含有很多维度表的星型模式有时被称为蜈蚣模式,显然这个名字也是因其形状而得来的。蜈蚣模式的维度表往往只有很少的几个属性,这样可以简化对维度表的维护,但查询数据时会有更多的表连接,严重时会使模型难于使用,因此在设计中应该尽量避免蜈蚣模式。
事实表
事实表记录了特定事件的数字化的考量,一般由数字值和指向维度表的外键组成。通常会把事实表的粒度级别设计的比较低,使得事实表可以记录很原始的操作型事件,但这样做的负面影响是累加大量记录可能会更耗时。事实表有以下三种类型:
- 事务事实表:记录特定事件的事实,如销售。
- 快照事实表:记录给定时间点的事实,如月底账户余额。
- 累积事实表:记录给定时间点的聚合事实,如当月的总的销售金额。
一般需要给事实表设计一个代理键作为每行记录的唯一标识。代理键是由系统生成的主键,它不是应用数据,没有业务含义,对用户来说是透明的。
维度表
维度表的记录数通常比事实表少,但每条记录包含有大量用于描述事实数据的属性字段。维度表可以定义各种各样的特性,以下是几种最长用的维度表:
- 时间维度表。描述星型模式中记录的事件所发生的时间,具有所需的最低级别的时间粒度。数据仓库是随时间变化的数据集合,需要记录数据的历史,因此每个数据仓库都需要一个时间维度表。
- 地理维度表:描述位置信息的数据,如国家、省份、城市、区县、邮编等。
- 产品维度表:描述产品及其属性。
- 人员维度表:描述人员相关的信息,如销售人员、市场人员、开发人员等。
- 范围维度表:描述分段数据的信息,如高级、中级、低级等。
通常给维度表设计一个单列、整型数字类型的代理键,映射业务数据中的主键。业务系统中的主键本身可能是自然键,也可能是代理键。自然键指的是由现实世界中已经存在的属性组成的键,如身份证号就是典型的自然键。
优点
星型模式是非规范化的,在星型模式的设计开发过程中,不受应用于事务型关系数据库的范式规则的约束。星型模式的优点如下:
- 简化查询。查询数据时,星型模式的连接逻辑比较简单,而从高度规范化的事务模型查询数据时,往往需要更多的表连接。
- 简化业务报表逻辑。与高度规范化的模式相比,由于查询更简单,因此星型模式简化了普通的业务报表(如每月报表)逻辑。
- 获得查询性能。星型模式可以提升只读报表类应用的性能。
- 快速聚合。基于星型模式的简单查询能够提高聚合操作的性能。
- 便于向立方体提供数据。星型模式被广泛用于高效地建立OLAP立方体,几乎所有的OLAP系统都提供ROLAP模型(关系型OLAP),它可以直接将星型模式中的数据当做数据源,而不用单独建立立方体结构。
缺点
星型模式的主要缺点是不能保证数据完整性。一次性地插入或更新操作可能会造成数据异常,而这种情况在规范化模型中是可以避免的。星型模式的数据装载,一般都是以高度受控的方式,用批处理或准实时过程执行的,以此来抵消数据保护方面的不足。
星型模式的另一个缺点是对于分析需求来说不够灵活。它更偏重于为特定目的建造数据视图,因此实际上很难进行全面的数据分析。星型模式不能自然的支持业务实体的多对多关系,需要在维度表和事实表之间建立额外的桥接表。
示例
假设有一个连锁店的销售数据仓库,记录销售相关的日期、商店和产品,其星型模式如图2-3所示。
图2-3 星型模式的销售数据仓库
Fact_Sales是唯一的事实表,Dim_Date、Dim_Store和Dim_Product是三个维度表。每个维度表的Id字段是它们的主键。事实表的Date_Id、Store_Id、Product_Id三个字段构成了事实表的联合主键,同时这个三个字段也是外键,分别引用对应的三个维度表的主键。Units_Sold是事实表的唯一一个非主键列,代表销售量,是用于计算和分析的度量值。维度表的非主键列表示维度的附加属性。下面的查询可以回答2020年各个城市的手机销量是多少。
select s.city as city, sum(f.units_sold)
from fact_sales f
inner join dim_date d on (f.date_id = d.id)
inner join dim_store s on (f.store_id = s.id)
inner join dim_product p on (f.product_id = p.id)
where d.year = 2020 and p.product_category = 'mobile'
group by s.city;
2.2.5 雪花模式
雪花模式是一种多维模型中表的逻辑布局,其实体关系图有类似于雪花的形状,因此得名。与星型模式相同,雪花模式也是由事实表和维度表所组成。所谓的“雪花化”就是将星型模式中的维度表进行规范化处理。当所有的维度表完成规范化后,就形成了以事实表为中心的雪花型结构,即雪花模式。将维度表进行规范化的具体做法是,把低基数的属性从维度表中移除并形成单独的表。基数指的是一个字段中不同值的个数,如主键列具有唯一值,所以有最高的基数,而象性别这样的列基数就很低。
在雪花模式中,一个维度被规范化成多个关联的表,而在星型模式中,每个维度由一个单一的维度表所表示。一个规范化的维度对应一组具有层次关系的维度表,而事实表作为雪花模式里的子表,存在具有层次关系的多个父表。
星型模式和雪花模式都是建立维度数据仓库或数据集市的常用方式,适用于加快查询速度比高效维护数据的重要性更高的场景。这些模式中的表没有特别的规范化,一般都被设计成一个低于第三范式的级别。
数据规范化与存储
规范化的过程就是将维度表中重复的组分离成一个新表,以减少数据冗余的过程。正因为如此,规范化不可避免地增加了表的数量。在执行查询的时候,不得不连接更多的表。但是规范化减少了存储数据的空间需求,而且提高了数据更新的效率。这点在前面介绍关系模型时已经进行了详细的讨论。
从存储空间的角度看,典型的情况是维度表比事实表小很多。这就使得雪花化的维度表相对于星型模式来说,在存储空间上的优势没那么明显了。举例来说,假设在220个区县的200个商场,共有100万条销售记录。星型模式的设计会产生1,000,200条记录,其中事实表1,000,000条记录,商场维度表有200条记录,每个区县信息作为商场的一个属性,显式地出现在商场维度表中。在规范化的雪花模式中,会建立一个区县维度表,该表有220条记录,商场表引用区县表的主键,有200条记录,事实表没有变化,还是1,000,000条记录,总的记录数是1,000,420(1,000,000+200+220)。在这种特殊情况下(作为子表的商场记录数少于作为父表的区县记录数),星型模式所需的空间反而比雪花模式要少。如果商场有10,000个,情况就不一样了,星型模式的记录数是1,010,000,雪花模式的记录数是1,010,220,从记录数上看,还是雪花模型多。但是,星型模式的商场表中会有10,000个冗余的区县属性信息,而在雪花模式中,商场表中只有10,000个区县的主键,而需要存储的区县属性信息只有220个,当区县的属性很多时,会大大减少数据存储占用的空间。
有些数据库开发者采取一种折中的方式,底层使用雪花模型,上层用表连接建立视图模拟星型模式。这种方法既通过对维度的规范化节省了存储空间,同时又对用户屏蔽了查询的复杂性。但是当外部的查询条件不需要连接整个维度表时,这种方法会带来性能损失。
优点
雪花模式是和星型模式类似的逻辑模型。实际上,星型模式是雪花模式的一个特例(维度没有多个层级)。某些条件下,雪花模式更具优势:
- 一些OLAP多维数据库建模工具专为雪花模型进行了优化。
- 规范化的维度属性节省存储空间。
缺点
雪花模型的主要缺点是维度属性规范化增加了查询的连接操作和复杂度。相对于平面化的单表维度,多表连接的查询性能会有所下降。但雪花模型的查询性能问题近年来随着数据浏览工具的不断优化而得到缓解。
和具有更高规范化级别的事务型模式相比,雪花模式并不确保数据完整性。向雪花模式的表中装载数据时,一定要有严格的控制和管理,避免数据的异常插入或更新。
示例
图2-4显示的是将图2-3的星型模式规范化后的雪花模式。日期维度分解成季度、月、周、日期四个表。产品维度分解成产品分类、产品两个表。由商场维度分解出一个地区表。
图2-4 雪花模式的销售数据仓库
下面所示的查询语句的结果等价于前面星型模式的查询,可以明显看到此查询比星型模式的查询有更多的表连接。
select g.city,sum(f.units_sold)
from fact_sales f
inner join dim_date d on f.date_id = d.id
inner join dim_store s on f.store_id = s.id
inner join dim_geography g on s.geography_id = g.id
inner join dim_product p on f.product_id = p.id
inner join dim_product_category c on p.product_category_id = c.id
where d.year = 2020 and c.product_category = 'mobile'
group by g.city;
2.3 Data Vault模型
Data Vault是一种数据仓库建模方法,用来存储来自多个操作型系统的完整的历史数据。Data Vault方法需要跟踪所有数据的来源,因此其中每个数据行都要包含数据来源和装载时间属性,用以审计和跟踪数据值所对应的源系统。Data Vault不区分数据在业务层面的正确与错误,它保留操作型系统的所有时间的所有数据,装载数据时不做数据验证、清洗等工作,这点明显有别于其它数据仓库建模方法。Data Vault建模方法显式地将结构信息和属性信息分离,能够还原业务环境的变化。Data Vault允许并行数据装载,不需要重新设计就可以实现扩展。
2.3.1 Data Vault模型简介
Data Vault(DV)模型用于企业级的数据仓库建模,是Dan Linstedt在20世纪90年代提出的。在最近几年,Data Vault模型获得了很多关注。Dan Linstedt将Data Vault模型定义如下:Data Vault是面向细节的,可追踪历史的,一组有连接关系的规范化的表的集合。这些表可以支持一个或多个业务功能。它是一种综合了第三范式(3NF)和星型模型优点的建模方法。其设计理念是要满足企业对灵活性、可扩展性、一致性和对需求的适应性要求,是一种专为企业级数据仓库量身定制的建模方式。
从上面的定义可以看出,Data Vault既是一种数据建模的方法论,又是构建企业数据仓库的一种具体方法。Data Vault模型由三个模块组成:中心表、链接表、附属表。建模方法论里定义了Data Vault的组成部分之间的交互方式。Data Vault的建模方法中还包括了最佳实践,来指导构建企业数据仓库。例如,业务规则应该在数据的下游实现,就是说Data Vault只按照业务数据的原样保存数据,不做任何解释、过滤、清洗、转换。即使从不同数据源来的数据是自相矛盾的(例如同一个客户有不同的地址),Data Vault模型不会遵照任何业务的规则,如“以系统A的地址为准”。Data Vault模型会保存两个不同版本的数据,对数据的解释将推迟到整个架构的后一个阶段(数据集市)。
2.3.2 Data Vault模型的组成部分
Data Vault模型有中心表(Hub)、链接表(Link)、附属表(Satellite)三个主要组成部分。中心表记录业务主键,链接表记录业务关系,附属表记录业务描述。
中心表
中心表用来保存一个组织内的每个实体的业务主键,业务主键唯一标识某个业务实体。中心表和源系统表是相互独立的。当一个业务主键被用在多个系统时,它在Data Vault中也只保留一份,其它的组件都是链接到这一个业务主键。这就意味着业务数据都集成到了一起。表2-13列出了中心表应该包含的所有的列。
属性 | 描述 |
主键 | 系统生成的代理键,供内部使用 |
业务主键 | 唯一标识的业务单元,用于已知业务的源系统 |
装载时间 | 数据第一次装载到数据仓库时系统生成的时间戳 |
数据来源 | 定义了数据来源(例如源系统或表) |
表2-13 中心表的属性
链接表
链接表是中心表之间的链接。一个链接表意味着两个或多个中心表之间有关联。一个链接表通常是一个外键,它代表着一种业务关系。表2-14列出了链接表的所有字段。
属性 | 描述 |
主键 | 系统生成的代理键,供内部使用 |
外键{1…N} | 引用中心表的代理键 |
装载时间 | 数据第一次装载到数据仓库时系统生成的时间戳 |
数据来源 | 定义了数据来源(例如源系统或表) |
表2-14 链接表的属性
在Data Vault里,每个关系都以多对多方式关联,这给模型带来了很大的灵活性。无论数据在源系统中是什么关系,都可以保存在Data Vault模型中。
附属表
附属表用来保存中心表和链接表的属性,包括所有的历史变化数据。一个附属表总有一个且唯一一个外键引用到中心表或链接表。表2-15列出了附属表的所有字段。
属性 | 描述 |
主键 | 系统生成的代理键,供内部使用 |
外键 | 引用中心表或链接表的代理键 |
装载时间 | 数据第一次装载到数据仓库时系统生成的时间戳 |
失效时间 | 数据失效时的时间戳 |
数据来源 | 定义了数据来源(例如源系统或表) |
属性{1…N} | 属性自身 |
表2-15 附属表的属性
在Data Vault模型的标准定义里,附属表的主键应该是附属表里参照到中心表或链接表的外键字段和装载时间字段的组合。尽管这个定义是正确的,但从技术角度考虑,我们最好还是增加一个代理键。使用只有一列的代理键更易维护。另外,对外键列和装载时间列联合建立唯一索引,也是一个好习惯。
2.3.3 Data Vault模型的特点
一个设计良好的Data Vault模型应该具有以下特点:
- 所有数据都基于时间来存储,即使数据是低质量的,也不能在ETL过程中处理掉。
- 依赖越少越好。
- 和源系统越独立越好。
- 设计上适合变化。
源系统中数据的变化。
在不改变模型的情况下可扩展。
- ETL作业可以重复执行。
- 数据完全可追踪。
2.3.4 Data Vault模型的构建
在Data Vault模型中,各个实体有着严格、通用的定义与准确、灵活的功能描述,这不但使得Data Vault模型能够最直观、最一般地反映数据之间内含的业务规则,同时也为构建Data Vault模型提供了一致而普遍的方法。
Data Vault模型的建立可以遵循如下步骤:
1. 设计中心表
首先要确定企业数据仓库要涵盖的业务范围;然后要将业务范围划分为若干原子业务实体,比如客户、产品等;然后,从各个业务实体中抽象出能够唯一标识该实体的业务主键,该业务主键要在整个业务的生命周期内不会发生变化;最后,由该业务主键生成中心表。
2. 设计链接表
链接表体现中心表之间的业务关联。设计链接表,首先要熟悉各个中心表代表的业务实体之间的业务关系,可能是两个或者多个中心表之间的关系。根据业务需求,这种关系可以是1对1、1对多、或者多对多的。然后,从相互之间有业务关系的中心表中,提取出代表各自业务实体的中心表主键,这些主键将被加入到链接表中,组合构成该链接表的主键。同样出于技术的原因,需要增加代理键。在生成链接表的同时,要注意如果中心表之间有业务交易数据的话,就需要在链接表中保存交易数据。有两种方法,一是采用加权链接表,二是给链接表加上附属表来处理交易数据。
3. 设计附属表
附属表包含了各个业务实体与业务关联的详细的上下文描述信息。设计附属表,首先要收集各个业务实体在提取业务主键后的其他信息,比如客户住址、产品价格等;由于同一业务实体的各个描述信息不具有稳定性,会经常发生变化,所以,在必要的时候,需要将变化频率不同的信息分隔开来,为一个中心表建立几个附属表,然后提取出该中心表的主键,作为描述该中心表的附属表的主键。当业务实体之间存在交易数据的时候,需要为没有加权的链接表设计附属表,也可以根据交易数据的不同变化情况设计多个附属表。
4. 设计必要的PIT表
Point—In—Time表是由附属表派生而来的。如果一个中心表或者链接表设计有多个附属表的话,而为了访问数据方便,就有用到PIT表的可能。PIT表的主键也是由其所归属的中心表提取而来,该中心表有几个附属表,PIT表就至少应该有几个字段来存放各个附属表的变化对比时间。
建立Data Vault模型时应该参照如下的原则:
关于中心表的原则
- 中心表的主键不能够直接“伸入”到其它中心表里面。就是说,不存在父子关系的中心表。各个中心表之间的关系是平等的,这也正是Data Vault模型灵活性与扩展性之所在。
- 中心表之间必须通过链接表相关联,通过链接表可以连接两个以上的中心表。
- 必须至少有两个中心表才能产生一个有意义的链接表。
- 中心表的主键总是“伸出去”的(到链接表或者附属表)。
关于链接表的原则
- 链接表可以跟其它链接表相连。
- 中心表和链接表都可以使用代理键。
- 业务主键从来不会改变,就是说中心表的主键也即链接表的外键不会改变。
关于附属表的原则
- 附属表必须是联接到中心表或者链接表上才会有确定的含义。
- 附属表总是包含装载时间和失效时间,从而包含历史数据,并且没有重复的数据。
- 由于数据信息的类型或者变化频率快慢的差别,描述信息的数据可能会被分隔到多个附属表中去。
2.3.5 Data Vault模型实例
下面用一个销售订单的例子说明如何将关系模型转换为Data Vault模型,以及如何向转换后的Data Vault模型装载数据。关系模型如图2-5所示,共有省、市、客户、产品类型、产品、订单、订单明细7个表。
图2-5 销售订单关系模型
将关系模型转换为Data Vault模型
首先按照下面的步骤转换中心表。
- 确定中心实体。示例中的客户、产品类型、产品、订单、订单明细这5个实体是订单销售业务的中心实体。省、市等地理信息表是参考数据,不能算是中心实体,实际上是附属表。
- 把第一步确定的中心实体中有入边的实体转换为中心表,因为这些实体被别的实体引用。把客户、产品类型、产品、订单转换成中心表。
- 把第一步确定的中心实体中没有入边且只有一条出边的实体转换为中心表。该示例中没有这样的表。
表2-16列出了所有中心表:
实体 | 业务主键 |
hub_product_catagory | product_catagory_id |
hub_customer | customer_id |
hub_product | product_id |
hub_sales_order | sales_order_id |
表2-16 销售订单中心表
每个中心表只有代理键、业务主键、装载时间、数据来源四个字段。在这个示例中,业务主键就是关系模型中表的主键字段。
然后按照下面的步骤转换链接表。
- 把示例中没有入边且有两条或两条以上出边的实体直接转换成链接表。符合条件的是订单明细表。
- 把示例中除第一步以外的外键关系转换成链接表。订单和客户之间建立链接表,产品和产品类型之间建立链接表。注意Data Vault模型中的每个关系都是多对多关系。
表2-17列出了所有链接表:
链接表 | 被链接的中心表 |
link_order_product | hub_sales_order、hub_product |
link_order_customer | hub_sales_order、hub_customer |
link_product_catagory | hub_product、hub_product_catagory |
表2-17 销售订单链接表
链接表中包含有代理键、关联的中心表的一个或多个主键、装载时间、数据来源等字段。
最后转换附属表。附属表为中心表和链接表补充属性。所有源库中用到的表的非键属性都要放到Data Vault模型的附属表中。表2-18列出了所有附属表:
附属表 | 所描述的表 |
sat_customer | hub_customer |
sat_product_catagory | hub_product_catagory |
sat_product | hub_product |
sat_sales_order | hub_sales_order |
sat_order_product | link_order_product |
表2-18 销售订单附属表
附属表中包含有代理键、关联的中心表或链接表的主键、装载时间、失效时间、数据来源、关联的中心表或链接表所对应的关系模型表中的一个或多个非主键属性等字段。
转换后的Data Vault模型如图2-6所示。
图2-6销售订单Data Vault模型
向Data Vault模型的表中装载数据
现在Data Vault模型的中心表、链接表、附属表都已经建立好,需要向其中装载数据,数据的来源是关系模型中的表。假设Data Vault的表使用MySQL数据库建立,代理键使用自增列,装载时间使用时间戳数据类型,在插入数据时,这两列不用显式赋值,数据会自动维护。数据来源字段简单处理,就填写与之相关的表名。附属表的失效时间字段,初始值填写一个很大的缺省时间,这里插入‘2200-01-01’。
使用以下的SQL代码装载hub_product中心表、link_order_product链接表、sat_order_product附属表,其它表的装载语句类似,这里从略。
-- 装载hub_product中心表
insert into hub_product (product_id,record_source)
select product_id,'product' from product;
-- 装载link_order_product链接表
insert into link_order_product(
hub_sales_order_id,
hub_product_id,
record_source)
select hub_sales_order_id,
hub_product_id,
'hub_sales_order,hub_product,sales_order_item'
from hub_sales_order t1,
hub_product t2,
sales_order_item t3
where t1.sales_order_id = t3.sales_order_id
and t2.product_id = t3.product_id;
-- 装载sat_order_product附属表
insert into sat_order_product (
link_order_product_id,
load_end_dts,
record_source,
unit_price,
quantity)
select link_order_product_id,
'2200-01-01',
'link_order_product,hub_sales_order,hub_product,sales_order_item',
t4.unit_price,
t4.quantity
from link_order_product t1,
hub_sales_order t2,
hub_product t3,
sales_order_item t4
where t1.hub_sales_order_id = t2.hub_sales_order_id
and t1.hub_product_id = t3.hub_product_id
and t4.sales_order_id = t2.sales_order_id
and t4.product_id = t3.product_id;
2.4 数据集市
在第1篇中介绍了独立数据集市和从属数据集市两种架构,本节继续讨论数据集市的概念、与数据仓库的区别、数据集市的设计等问题。
2.4.1 数据集市的概念
数据集市是数据仓库的一种简单形式,通常由组织内的业务部门自己建立和控制。一个数据集市面向单一主题域,如销售、财务、市场等。数据集市的数据源可以是操作型系统(独立数据集市),也可以是企业级数据仓库(从属数据集市)。
2.4.2 数据集市与数据仓库的区别
不同于数据集市,数据仓库处理整个组织范围内的多个主题域,通常是由组织内的核心单位,如IT部门承建,所以经常被称为中心数据仓库或企业数据仓库。数据仓库需要集成很多操作型源系统中的数据。由于数据集市的复杂度和需要处理的数据都小于数据仓库,因此更容易建立与维护。表2-19总结了数据仓库与数据集市的主要区别。
对比项 | 数据仓库 | 数据集市 |
范围 | 企业级 | 部门级或业务线 |
主题 | 多个主题 | 单一主题 |
数据源 | 遗留系统、事务系统、外部数据的多个数据源 | 数据仓库或事务系统的少量数据源 |
数据粒度 | 较细的粒度 | 较粗的粒度 |
数据结构 | 通常是规范化结构(3NF) | 星型模型、雪花模型、或两者混合 |
历史数据 | 全部历史数据 | 部分历史数据 |
完成需要的时间 | 几个月到几年 | 几个月 |
表2-19 数据仓库与数据集市的主要区别
2.4.3 数据集市设计
数据集市主要用于部门级别的分析型应用,数据大都是经过了汇总和聚合操作,粒度级别较高。数据集市一般采用维度模型设计方法,数据结构使用星型模式或雪花模式。
正如前面所介绍的,设计维度模型先要确定维度表、事实表和数据粒度级别,下一步是使用主外键定义事实表和维度表之间的关系。数据集市中的主键最好使用系统生成的自增的单列数字型代理键。模型建立好之后,设计ETL步骤抽取操作型源系统的数据,经过数据清洗和转换,最终装载进数据集市中的维度表和事实表中。
2.5 数据仓库实施步骤
实施一个数据仓库项目的主要步骤是:定义项目范围、收集并确认业务需求和技术需求、逻辑设计、物理设计、从源系统向数据仓库装载数据、使数据可以被访问以辅助决策、管理和维护数据仓库。
1. 定义范围
在实施数据仓库前,需要制定一个开发计划。这个计划的关键输入是信息需求和数据仓库用户的优先级。当这些信息被定义和核准后,就可以制作一个交付物列表,并给数据仓库开发团队分配相应的任务。
首要任务是定义项目的范围。项目范围定义了一个数据仓库项目的边界。典型的范围定义是组织、地区、应用、业务功能的联合表示。定义范围时通常需要权衡考虑资源(人员、系统、预算等)、进度(项目的时间和里程碑要求)、功能(数据仓库承诺达到的能力)三方面的因素。定义好清晰明确的范围,并得到所有项目干系人的一致认可,对项目的成功是非常重要的。项目范围是设定正确的期望值、评估成本、估计风险、制定开发优先级的依据。
2. 确定需求
数据仓库项目的需求可以分为业务需求和技术需求。
(1)定义业务需求
建立数据仓库的主要目的是为组织赋予从全局访问数据的能力。数据的细节程度必须能够满足用户执行分析的需求,并且数据应该被表示为用户能够理解的业务术语。对数据仓库中数据的分析将辅助业务决策,因此,作为数据仓库的设计者,应该清楚业务用户是如何做决策的,在决策过程中提出了哪些问题,以及哪些数据是回答这些问题所需要的。与业务人员进行面对面的沟通,是理解业务流程的好方式,沟通的结果是使数据仓库的业务需求更加明确。在为数据仓库收集需求的过程中,还要考虑设计要能适应需求的变化。
(2)定义技术需求
数据仓库的数据来源是操作型系统,这些系统日复一日地处理着各种事务活动。操作型系统大都是联机事务处理系统。数据仓库会从多个操作型源系统抽取数据。但是,一般不能将操作型系统里的数据直接迁移到数据仓库,而是需要一个中间处理过程,这就是所谓的ETL过程。需要知道如何清理操作型数据,如何移除垃圾数据,如何将来自多个源系统的相同数据整合在一起。另外,还要确认数据的更新频率。例如,如果需要进行长期的或大范围的数据分析,可能就不需要每天装载数据,而是每周或每月装载一次。注意,更新频率并不决定数据的细节程度,每周汇总的数据有可能每月装载(当然这种把数据转换和数据装载分开调度的做法并不常见)。在数据仓库设计的初始阶段,需要确定数据源有哪些、数据需要做哪些转换以及数据的更新频率是什么。
3. 逻辑设计
定义了项目的范围和需求,就有了一个基本的概念设计。下面就要进入数据仓库的逻辑设计阶段。逻辑设计过程中,需要定义特定数据的具体内容,数据之间的关系,支持数据仓库的系统环境等,本质是发现逻辑对象之间的关系。
(1)建立需要的数据列表
细化业务用户的需求以形成数据元素列表。很多情况下,为了得到所需的全部数据,需要适当扩展用户需求或者预测未来的需要,一般从主题域涉及的业务因素入手。例如,销售主题域的业务因素可能是客户、地区、产品、促销等。然后建立每个业务因素的元素列表,依据也是用户提出的需求。最后通过元素列表,标识出业务因素之间的联系。这些工作完成后,应该已经获得了如下的信息:原始的或计算后的数据元素列表;数据的属性,比如是字符型的还是数字型的;合理的数据分组,比如国家、省市、区县等分成一组,因为它们都是地区元素;数据之间的关系,比如国家、省市、区县的包含关系等。
(2)识别数据源
现在已经有了需要的数据列表,下面的问题是从哪里可以得到这些数据,以及要得到这些数据需要多大的成本。需要把上一步建立的数据列表映射到操作型系统上。应该从最大最复杂的源系统开始,在必要时再查找其它源系统。数据的映射关系可能是直接的或间接的。比如销售源系统中,商品的单价和折扣价可以直接获得,而折扣百分比就需要计算得到。通常维度模型中的维度表可以直接映射到操作型源系统,而事实表的度量则映射到源数据在特定粒度级别上聚合计算后的结果。某些数据的获得需要较高的成本,例如,用户想要得到促销相关的销售数据就不那么容易,因为促销期的定义从时间角度看是不连续的。
(3)制作实体关系图
逻辑设计的交付物是实体关系图(entity-relationship diagram,简称ERD)和对它的说明文档(数据字典)。实体对应关系数据库中的表,属性对应关系数据库中的列。ERD传统上与高度规范化的关系模型联系密切,但该技术在维度模型中也被广泛使用。在维度模型的ERD中,实体由事实表和维度表组成,关系体现为在事实表中引用维度表的主键。因此先要确认哪些信息属于中心事实表,哪些信息属于相关的维度表。维度模型中表的规范化级别通常低于关系模型中的表。
4. 物理设计
物理设计指的是将逻辑设计的对象集合,转化为一个物理数据库,包括所有的表、索引、约束、视图等。物理数据库结构需要优化以获得最佳性能。每种数据库产品都有自己特别的优化方法,这些优化对查询性能有极大的影响。比较通用的数据仓库优化方法有位图索引和表分区。
第1篇中的“分析型系统的数据库设计”已经提到过位图索引和表分区。位图索引对索引列的每个不同值建立一个位图。和普通的B树索引相比,位图索引占用的空间小,创建速度快。但由于并发的DML操作会锁定整个位图段的大量数据行,所以位图索引不适用于频繁更新的事务处理系统。而数据仓库对最终用户来说是一个只读系统,其中某些维度的值基数很小,这样的场景非常适合利用位图索引优化查询。遗憾的是有些数据库管理系统如MySQL,还没有位图索引功能。
大部分数据库系统都可以对表进行分区。表分区是将一个大表按照一定的规则分解成多个分区,每个表分区可以定义独立的物理存储参数。将不同分区存储到不同的磁盘上,查询表中数据时可以有效分布I/O操作,缓解系统压力。分区还有一个很有用的特性,叫做分区消除。查询数据的时候,数据库系统的优化器可以通过适当的查询条件过滤掉一些分区,从而避免扫描所有数据,提高查询效率,这就是分区消除。
除了性能优化,数据仓库系统的可扩展性也非常重要。简单地说,可扩展性就是能够处理更大规模业务的特性。从技术上讲,可扩展性是一种通过增加资源,使服务能力得到线性扩展的能力。比方说,一台服务器在满负荷时可以为一万个用户同时提供服务,当用户数增加到两万时,只需要再增加一台服务器,就能提供相同性能的服务。成功的数据仓库会吸引越来越多的用户访问。随着时间的推移,数据量会越来越大,因此在做数据仓库物理设计时,出于可扩展性的考虑,应该把对硬件、软件、网络带宽的依赖降到最低。第3篇会详细讨论数据仓库在Greenplum上的扩展性问题。
5. 装载数据
这个步骤实际上涉及整个ETL过程。需要执行的任务包括:源和目标结构之间建立映射关系;从源系统抽取数据;对数据进行清洗和转换;将数据装载进数据仓库;创建并存储元数据。
6. 访问数据
访问步骤是要使数据仓库的数据可以被使用,使用的方式包括:数据查询、数据分析、建立报表图表,数据发布等。根据采用的数据仓库架构,可能会引入数据集市的创建。通常,最终用户会使用图形化的前端工具向数据库提交查询,并显示查询结果。访问步骤需要执行以下任务:
- 为前端工具建立一个中间层。在这个中间层里,把数据库结构和对象名转化成业务术语,这样最终用户就可以使用与特定功能相关的业务语言同数据仓库交互。
- 管理和维护这个业务接口。
- 建立和管理数据仓库里的中间表和汇总表。建立这些表完全是出于性能原因。中间表一般是在原始表上添加过滤条件获得的数据集合,汇总表则是对原始表进行聚合操作后的数据集合。这些表中的记录数会远远小于原始表,因此前端工具在这些表上的查询会执行得更快。
7. 管理维护
这个步骤涵盖在数据仓库整个生命周期里的管理和维护工作。这步需要执行的任务包括:确保对数据的安全访问;管理数据增长;优化系统以获得更好的性能;保证系统的可用性和可恢复性等。
2.6 小结
- 关系模型、多维模型和Data Vault模型是三种常见的数据仓库模型。
- 数据结构、完整性约束和SQL语言是关系模型的三个要素。
- 规范化是通过应用范式规则实现的。第一范式(1NF)要求保持数据的原子性、第二范式(2NF)消除了部分依赖、第三范式(3NF)消除了传递依赖。关系模型的数据仓库一般要求满足3NF。
- 事实、维度、粒度是维度模型的三个核心概念。
- 维度模型的四步设计法是选择业务流程、声明粒度、确定维度、确定事实。
- 星型模式和雪花模式是维度模型的两种逻辑表示。对星型模式进一步规范化,就形成了雪花模式。
- Data Vault模型有中心表(Hub)、链接表(Link)、附属表(Satellite)三个主要组成部分。中心表记录业务主键,链接表记录业务关系,附属表记录业务描述。
- Data Vault不区分数据在业务层面的正确与错误,它保留操作型系统的所有时间的所有数据,装载数据时不做数据验证、清洗等工作。
- 数据集市是部门级的、面向单一主题域的数据仓库。
- 数据集市的复杂度和需要处理的数据都小于数据仓库,因此更容易建立与维护。
- 实施一个数据仓库项目的主要步骤是:定义范围、确认需求、逻辑设计、物理设计、装载数据、访问数据、管理维护。