数据库(Database)是按照数据结构来组织、存储和管理数据的建立在计算机存储设备上的仓库。
数据库是长期储存在计算机内、有组织的、可共享的数据集合。数据库的数据指的是以一定的数据模型组织、描述和储存在一起、具有尽可能小的冗余度、较高的数据独立性和易扩展的特点并可在一定范围内为多个用户共享。
常用的数据库有 MySQL、ORACLE、SQL Server 等。
数据仓库是决策支持系统(dss)和联机分析应用数据源的结构化数据环境。数据仓库研究和解决从和数据库中获取信息的问题。
数据仓库的特征在于面向主题、集成性、稳定性和时变性,用于支持管理决策。
数据仓库存在的意义在于对企业的所有数据进行汇总,为企业各个部门提供统一的、规范的数据出口。
面向主题:数据仓库中的数据是按照一定的主题域进行组织的,每一个主题对应一个宏观的分析领域。数据仓库排除对于决策无用的数据,提供特定主题的简明视图。
集成的:企业内不同业务部门数据的完整集成。
对于企业内所有数据的集成要注意一致性(假设财务系统中对于性别使用 F/M,而 OA 系统对性别使用 A/B,这就是数据不一致,如果想搭建企业级的数据仓库,需要数据具有一致性)。
稳定的:数仓里不存在数据的更新和删除操作。
变化的:数仓里会完整的记录某个对象在一段时期内的变化情况。
数据仓库的目标是实现集成、稳定、反映历史变化有组织有结构的存储数据的集合。
如上图所示,一个公司可能有多个业务系统,而数据仓库就是将所有的业务系统按照某种组织架构整合起来,形成一个仓储平台,也就是数仓。
ODS—脱敏/清洗—DWD—汇总—DWS—汇总/宽表—DM
ODS(Operational Data Store):操作数据存储层,往往是业务数据库表格的一对一映射,将业务数据库中的表格在 ODS 重新建立,数据完全一致;
DWD(Data Warehouse Detail):数据明细层,在 DWD 进行数据的清洗、脱敏、统一
化等操作,DWD 层的数据是干净并且具有良好一致性的数据;mapreduce
DWS(Data Warehouse Service):服务数据层(公共汇总层),在 DWS 层进行轻度汇总,为 DM 层中的不同主题提供公用的汇总数据;
DM(Data Market):数据集市层,DM 层针对不同的主题进行统计报表的生成;
OLTP(On-Line Transaction Processing)即联机事务处理 ,也可以称面向交易的处理系统,它是针对具体业务在数据库联机的日常操作,通常对少数记录进行查询、修改。用户较为关心操作的响应时间、数据安全性、完整性和并发支持的用户数量等问题。传统的数据库系统作为数据管理的主要手段,主要用OLTP。
OLTA(On-Line Analytical Processing)即联机分析处理,一般针对某些主题的历史数据进行分析,支持管理决策。
OLTP与OLTA的异同
关系型数据库设计时,遵照一定的规范要求,目的在于降低数据的冗余性和数据的一致性,目前业界范式有:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)、第五范式(5NF)。
范式的标准定义是:符合某一种级别的关系模式的集合,表示一个关系内部各属性之间的联系的合理化程度。通俗地讲,范式可以理解为一张数据表的表结构所符合的某种设计标准的级别。
使用范式的根本目的是:减少数据冗余,尽量让每个数据只出现一次,获取数据时通过 join 拼接出最后的数据。
一范式(1NF):域应该是原子性的,即数据表的每一列都是不可分割的原子数据项。
注:域就是列的取值范围,比如性别的域就是(男,女)
数据表中的所有列保持其原子性,不可再分。
很明显如上图所示的表格设计是不符合第一范式的,商品列中的数据不是原子数据项,是可以进行分割的,因此对表格进行修改,让表格符合第一范式的要求,修改结果如下图所示
实际上,1NF是所有关系型数据库的最基本要求,你在关系型数据库管理系统(RDBMS),例如 SQL Server,Oracle,MySQL 中创建数据表的时候,如果数据表的设计不符合这个最基本的要求,那么操作一定是不能成功的。也就是说,只要在 RDBMS 中已经存在的数据表,一定是符合 1NF 的。
二范式(2NF):在1NF的基础上,实体的属性完全函数依赖于主关键字(混合主键),不能存在部分函数依赖于主关键字(混合主键)。
如果存在某些属性只依赖混合主键中的部分属性,那么不符合二范式。
上述表格中是混合主键(学生 ID + 所修课程),但是所属系和系主任这两个属性只依赖于混合主键中的学生 ID 这一个属性,因此,不符合第二范式。
如果有一天学生的所属系要调整,那么所属系和系主任这两列都需要修改,如果这个学生修了多门课程,那么表中的多行数据都要修改,这是非常麻烦的,不符合第二范式。
为了消除这种部分依赖,只有一个办法,就是将大数据表拆分成两个或者更多个更小的数据表。
通过上述的修改,当一个学生的所属系需要调整时,不管学生修了多少门课程,都只需要改变表中的一行数据即可。
3NF 在 2NF 的基础之上,消除了非主属性对于主键(复合主键)的传递依赖
很明显,表中商品颜色依赖于商品 ID,商品 ID 依赖于订单 ID,那么非主属性商品颜色就传递依赖于订单 ID,因此不符合三范式,解决方案是将大数据表拆分成两个或者更多个更小的数据表。
数据仓库建模的目标是通过建模的方法更好的组织、存储数据,以便在性能、成本、效率和数据质量之间找到最佳平衡点。
访问性能:能够快速查询所需的数据,减少数据 I/O;DM集市(hbase ES)mysql
数据成本:减少不必要的数据冗余,实现计算结果数据复用,降低大数据系统中的数据成本和计算成本;
使用效率:改善用户应用体验,提高使用数据的效率;
数据质量:整合所有数据源的数据,改善数据统计口径的不一致性,减少数据计算错误的可能性,提供高质量的、一致的数据访问平台。
上述的四点之间是存在冲突的,为了提高访问性能,可能会提高数据冗余(减少 Join), 这样会降低计算成本,但是会导致数据存储成本很高,并且由于数据的冗余,会提高数据统计口径不一致的风险,我们的目的是通过合理的设计在性能、成本、效率和数据质量之间找到平衡点。
1、基本理论
ER 模型是数据库设计的理论基础,当前几乎所有的 OLTP 系统设计都采用 ER 模型建模的方式。
在信息系统中,将事物抽象为“实体”、“属性”、“关系”来表示数据关联和事物描述;其中,实体:Entity,关系:Relationship,这种对数据的抽象建模通常被称为 ER 实体关系模型。
实体:通常为参与到过程中的主体,客观存在的,比如商品、仓库、货位、汽车,此实体非数据库的实体表;
属性:对主体的描述、修饰即为属性,比如商品的属性有商品名称、颜色、尺寸、重量、产地等;
关系:现实的物理事件是依附于实体的,比如商品入库事件,依附实体商品、货位, 就会有“库存”的属性产生;用户购买商品,依附实体用户、商品,就会有“购买数量”、“金额”的属性产品。
2、实体之间的对照关系
实体之间建立关系时,存在对照关系:
1:1,即 1 对 1 的关系,比如实体人、身份证,一个人有且仅有一个身份证号;(A->B: 相互完全依赖,知道 A 一定确定 B,知道 B 一定确定 A)。
(动静分离:在数据库设计时,会将动态属性(年龄、地址、偏好、...)和静态属性(姓名、性别、身份证号、...)进行分离,剥离为两张表,一张父表,一张子表,从而提高性能)。
1:n,即 1 对多的关系,比如实体学生、班级,对于某 1 个学生,仅属于 1 个班级,而在 1 个班级中,可以有多个学生;(一张学生表,一张班级表,通过班级 ID 这个外键进行关联)。
n:m,即多对多的关系,比如实体学生、课程,每个学生可以选修多门课程,同样每个课程也可以被多门学生选修;(一张学生表,一张课程表,一张选课表)。
3、ER 建模的图形表示
在日常建模过程中:
“实体”:使用矩形表示;
“关系”:使用菱形表示;
“属性”:使用椭圆形表示;
所以 ER 实体关系模型也称作 E-R 关系图。
1、场景
学生选课系统,该系统主要用来管理学生和选修课程,其中包括课程选修、学生管理功能,现需要完成数据库逻辑模型设计。
2、实现步骤
使用 ER 模型构建数据仓库的成功率是比较低的,因为涉及到“抽象出实体”这个过程, 这就涉及到将企业所有业务系统中的所有实体都抽象出来,这需要先梳理出所有的业务系 统实体,再梳理实体之间的关系,这是一个非常复杂的过程,可能你把公司所有的实体梳 理清楚了,可能业务又要调整了。
维度建模的理论由 Ralph Kimball 提出,他提出将数据仓库中的表划分为事实表和维度表两种类型。
维度建模源自数据集市,主要面向分析场景。
“事实表”,用来存储事实的度量(measure)及指向各个维的外键值。“维度表”, 用来保存该维的元数据,即维的描述信息,包括维的层次及成员类别等。
简单的说,维度表就是你观察该事物的角度(维度),事实表就是你要关注的内容。例如用户使用滴滴打车,那么打车这件事就可以转化为一个事实表,即打车订单事实表,然后用户对应一张用户维度表,司机对应一张司机维度表。
1、事实表
在现实世界中,每一个操作型数事件,基本都发生在实体之间的,伴随着这种操作事件的发生,会产生可度量的值,而这个过程就产生了一个事实表,存储了每一个可度量的事件。
将发生在现实世界中的操作性事件所产生的可度量的数值,存储在事实表中,从最低的粒度级别来看,事实表行对应一个度量事件,反之亦然。因此,事实表的设计完全依赖于物理活动,不受可能产生的最终报表的影响。除数字度量外,事实表总是包含外键,用于关联与之相关的维度,也包含可选的退化维度键和日期/时间戳。查询请求的主要目标是基于事实表展开计算和聚集操作。
事实表往往包含三个重要元素:
例如在电商场景中的一次购买事件,涉及主体包括客户、商品、商家,产生的可度量值包括商品数量、金额、件数等。
2、维度表
每个维度表都包含着单一的主键列。维度表的主键可以作为与之关联的任何事实表的外键,当然,维度表行的描述环境应与事实表行完全对应。维度表通常比较宽,是扁平型非常规表,包含大量坻粒度的文本属性。
比如商品,单一主键为商品 ID,属性包括产地、颜色、材质、尺寸、单价等,但并非属性一定是文本,比如单价、尺寸,均为数值型描述性的,日常主要的维度抽象包括:时间维度表、地理区域维度表等。
综上所述,如果针对用户的下单行为(单一商品)进行维度建模,我们可以得到如下模型:
1、背景
某电商平台,经常需要对订单进行分析,以某宝的购物订单为例,以维度建模的方式设计该模型。
2、事实表与维度表的划分
事实表为订单表、子订单表,维度包括商品维度、用户维度、商家维度、区域维度、时间维度。
3、事实表分析
订单中包含的度量:商品件数、总金额、总减免金额; 描述性属性:下单时间、付款时间、订单状态等;
子订单包含度量:商品 ID、单价、减免金额;
描述性属性:加入购物车时间、下单时间、付款时间、状态;
4、维度表分析
商品维度:商品 ID、商品名称、商品品类、单价、颜色、尺寸、生产商等; 用户维度:用户 ID、姓名、性别、生日、职业、信用值、收货地址等;
用户维度:用户 ID、姓名、性别、生日、职业、信用值、收货地址等;
时间维度:日期 ID、日期、周几、是否周末、是否假期等; 区域维度:区域 ID,县/区、县/区 ID、市、市 ID、省、省 ID;
区域维度:区域 ID,县/区、县/区 ID、市、市 ID、省、省 ID;
订单表和子订单表是两张事实表,我们往往会避免事实表之间产生关系,因此会考虑 让子订单表中有一定的数据冗余,比如订单表和订单明细表都各自记录着用户 ID,区域 ID, 时间 ID 等,这样在查询子订单信息时,就不用通过关联订单表来获取上述数据了,但是子订单表中仍会保存订单 ID 字段。
ER 模型以及维度模型是当前主流的建模方法。
ER 模型常用于 OLTP 数据库建模,应用到构建数仓时更偏重数据整合,站在企业整体考虑,将各个系统的数据按相似性、一致性合并处理,为数据分析、决策服务,但并不便于直接用来支持分析。
ER 模型的特点如下:
维度建模是面向分析场景而生,针对分析场景构建数仓模型;重点关注快速、灵活的解决分析需求,同时能够提供大规模数据的快速响应性能。针对性强,主要应用于数据仓库构建和 OLAP 引擎低层数据模型。
星型模式是维度模型中最简单的形式,也是数据仓库以及数据集市开发中使用最广泛的形式。星型模式由事实表和维度表组成,一个星型模式中可以有一个或多个事实表,每个事实表引用任意数量的维度表。星型模式的物理模型像一颗星星的形状,中心是一个事实表, 围绕在事实表周围的维度表表示星星的放射状分支,这就是星型模式这个名字的由来。
星型模式将业务流程分为事实和维度。事实包含业务的度量,是定量的数据,如销售价格、销售数量、距离、速度、重量等是事实。维度是对事实数据属性的描述,如日期、产品、客户、地理位置等是维度。一个含有很多维度表的星型模式有时被称为蜈蚣模式,显然这个名字也是因其形状而得来的。蜈蚣模式的维度往往只有很少的几个属性,这样可以简化对维度表的维护,但查询数据时会有更多的表连接,严重时会使模型难于使用,因此在设计中应该尽量避免蜈蚣模式。
雪花模式是一种多维模型中表的逻辑布局,其实体关系图有类似于雪花的形状,因此得名。
与星型模式相同,雪花模式也是由事实表和维度表所组成。所谓的“雪花化”就是将行星模型中的维度表进行规范化处理。当所有的维度表完成规范化后,就形成了以事实表为
中心的雪花型结构,即雪花模式。将维度表进行规范化的具体做法是,把低基数的属性从维度表中移除并形成单独的表。基数指的是一个字段中不同值的个数,如主键列具有唯一值, 所以有最高的基数,而像性别这样的列基数就很低。
在雪花模式中,一个维度被规范化成多个关联的表,而在星型模式中,每个维度由一个单一的维度表所表示。一个规范化的维度对应一组具有层次关系的维度表,而事实表作为雪花模式里的字表,存在具有层次关系的多个父表。
数据仓库由多个主题构成,包含多个事实表,而维表是公共的,可以共享,这种模式可以看做星型模式的汇集,因而称作星系模式或者事实星座模式。
在数据仓库建模时,会涉及到模式的选择,我们要根据不同模式的特点选择适合具体业务的模式:
冗余:雪花模型符合业务逻辑设计,采用 3NF 设计,有效降低数据冗余;星型模型的维度表设计不符合 3NF(如果是雪花模型改造成了星型模型,那么肯定不符合 3NF,因为一定发生了表的整合,即降维,一定有传递依赖,但是,并不是所有的星型模型都不符合3NF,很多星型模型的表是符合 3NF 的),反规范化,维度表之间不会直接相关,牺牲部分存储空间。(雪花模型的维度之间是有关联的)
性能:雪花模型由于存在维度间的关联,采用 3NF 降低冗余,通常在使用过程中,需要连接更多的维度表,导致性能偏低;星型模型反三范式,采用降维的操作将维度整合,以存储空间为代价有效降低维度表连接数,性能较雪花模型高。( 星型表的数据冗余大,是用存储空间换取效率 )( BI 的一些工具对于星型模型的支持更规范化 )
ETL:雪花模型符合业务 ER 模型设计原则,在 ETL 过程中相对简单,但是由于附属模型的限制,ETL 任务并行化较低(由于雪花模型中有很多的维度依赖,在 ETL 的时候, 需要在保持 3NF 的前提下对数据进行清洗,即对数据一致性/规范化的处理,例如数据来自于多个业务系统,各个系统对于用户的定义不一致,此时要对每个业务定义的用户数据进行规范化处理,在 3NF 的限制下必然会降低并行度);星型模型在设计维度表时反范式设计,所以在 ETL 过程中整合业务数据到维度表有一定难度,但由于避免附属维度,可并行化处理(不用关注太多的关联关系,避免了维度表之间的关联关系,并行度较高,注意,一般场景下星型模型的并行化程度更高,并不是所有场景)。
Hive 的分析通过 MapReduce 实现,每多一个 Join 就会多出一个 MapReduce 过程,对于雪花模型,由于存在着很多维度表之间的关联,这就会导致一次分析对应多个 MapReduce 任务,而星型模型由于不存在维度表的关联,因此一个 MapReduce 就可以实现分析任务。MapReduce 本身是一个支持高吞吐量的任务,它的每个任务都要申请资源、分配容器、节点通信等待,需要 YARN 的调度,由于相互关联的维度表本身会很小,join 操作用时很少,YARN 调度的时长可能都大于实际运算的时长,因此我们要尽可能减少任务个数,对于 Hive 来说就是尽可能减少不必要的表的关联。还有一点,雪花模型中拆分出的维度表,每个表对应至少一个文件,这就涉及到 I/O 方面的性能损耗。
因此,我们要采用适当的数据冗余,避免不必要的表之间的关联。
在实际项目中,不会刻意地去考虑雪花模型,而是刻意地去考虑星型模型,特别是大数据领域的建模,倾斜于使用数据冗余来提高查询效率,倾向于星型模型;雪花模型只会应用在一些我们要求模型的灵活性,要求保证模型本身稳定性的场景下,但是雪花模型并不是首选。
维度表中必须有一个能够唯一标识一行记录的列(最好是原子性的列,不要是组合键), 通过该列维护维度表与事实表之间的关系,一般在维度表中业务主键符合条件可以当作维度主键。
但是,数据仓库是整个公司数据的整合,这会涉及到多个数据源有相同维度,那么就会出现以下两个问题:
当整合多个数据源的维度时,不同数据源的业务主键重复怎么办?
涉及维度拉链表时,同一主体多条记录,业务键重复怎么办?
如上图所示,业务键重复,我们可以引入代理键,如下表所示:
把多个系统的数据复合在一起,同时再维护一个代理键,而且代理键在这个维度表里是唯一标识一条记录的,类似于业务系统的业务键。
代理键是由数据仓库处理过程中产生的、与业务本身无关的、唯一标识维度表中一条记录并充当维度表主键的列,也是描述维度表与事实表关系的纽带。
在设计有代理键的维度表中,事实表中的关联键是代理键而不是原有的业务主键,即
业务关系是靠代理键维护,这样有效避免源系统变化对数仓数据对影响。
在实际业务中,代理键通常是数值型、自增的值。
部分维度表的维度是在维度表产生后,属性是稳定的、无变化的。比如时间维度、区 域维度等,针对这种维度,设计维度表的时候,仅需要完整的数据,不需要天的快照数据, 因为当前数据状态就是历史数据状态。
维度数据会随着时间发生变化,变化速度比较缓慢,这种维度数据通常称作缓慢渐变维,例如电商平台的用户维度表,用户可能会随着时间推移改变收件地址,因此用户维度表中的收件地址就是一个缓慢变化维。由于数据仓库需要追溯历史变化,尤其是一些重要的数据,所以历史状态也需要采取一定的措施进行保存,保存历史状态的方式有以下三种:
拉链表:当维度数据发生变化时,将旧数据置为失效,将更改后的数据当作新的记录插入到维度表中,并开始生效,这样能够记录数据在某种粒度上的变化历史。
将数据的变更当做流水记录下来 ,旧的设为失效,新的设为生效,如果粒度为天,那么就可以得到一天的最终状态作为最终状态。
表中每条记录都有一个 End_date,当有新的数据产生时,在旧数据的 End_date 字段中插入日期,然后新插入一条数据,新数据的 End_date 字段中是一个永久有效的值,如果再发生更新,上一次更新数据的 End_date 字段设置为当前日期,然后再次插入新数据, 新数据的 End_date 字段中设置一个永久有效的值。
如果想知道某个员工在 5 月 22 号时在哪个部门,那么可以通过如下 SQL:Select * from user where start_date<= 2018-05-22 and end_date>= 2018-05-22
根据拉链表的结构,如果对维度表做拉链,那么一个维度实体必然存在多条记录,也就是一个主键 ID 对应多条数据,此时维度表的原子性主键也就没有意义了。
维度表做拉链后会失去原子性主键,那么拉链维度表如何和事实表进行关联呢? 此时就要用到代理键,也就是在事实表和维度表中同时添加代理键,如下图所示:
完成代理键的添加后,在之后的统计中,按照代理键进行聚合即可。
事实表来源于业务事务表,代理键和业务本身没有关系,那么怎么在新增数据时在事实表中装载代理键?
当事实表中有新增数据时,新增数据中记录了维度表中原有的原子性主键,可以根据原有的主键匹配维度表中的数据,然后根据新增数据的时间范围找到匹配的代理键,然后在事实表的新增数据中加入代理键。
代理键是维度建模中极力推荐的方式,它的应用能有效的隔离源端变化带来的数仓结构不稳定问题,同时也能够提高数据检索性能。但是代理键维护代价非常高,尤其是数据装载过程中,对事实表带来了较大的影响, 在基于 hive 的数据仓库建设影响更加严重,比如代理键的生成、事实表中关联键的装载、不支持非等值关联等问题,带来 ETL 过程更加复杂。
因此,在大数据体系下,谨慎使用代理键,同时对于缓慢渐变维场景,可以考虑用空间换取时间,每天保留维表全量快照,但这样会带来存储成本,根据实际情况衡量。