码迷,mamicode.com
首页 > 其他好文 > 详细

2. 数仓理论

时间:2020-08-28 14:29:13      阅读:47      评论:0      收藏:0      [点我收藏+]

标签:冗余   基于   职位   组合   原因   避免   shu   设计   交互   

范式理论

范式可以理解为设计一张符合标准级别的数据表结构时,所需要遵循的规范和要求。

而在关系型数据库设计时遵照一定的规范要求,可以带来很多好处。比如:降低数据的冗余性:

  • 1. 因为数据冗余度高的话, 会增大磁盘开销
  • 2. 在不使用分布式系统的情况下, 数据冗余度高的话, 可能需要增加磁盘的数量, 而单机的磁盘个数是有限的
  • 3. 数据冗余度高的话, 会导致一次修改需要修改多个表, 很难保证数据的一致性

举个栗子:

技术图片

假设有两张表,一张表存储用户的信息和购买过的商品、数量、以及金额;另一张表存放的是用户信息和它评价了哪些商品、搜藏了哪些商品。但是我们看到这样做会造成数据冗余,因为用户信息被存储了两次,所以这个时候可以将用户的信息单独抽出来作为一张用户表,并设置一个用户id。然后别的表只需要存储用户id即可,这样可以避免不必要的数据存储。

而且当用户修改信息之后,只需要更新用户表的信息即可,不会影响其它的表。但如果不把用户信息单独作为一张表的话,那么当用户修改信息时每张表都需要改一遍。

所以在如果设计上不遵循规范的话,那么就会造成许多问题,再举个栗子:

技术图片

这种表设计相当于将员工信息、所在部门以及职位信息都存储到一个表中了,显然会存在如下问题:

  • 数据冗余: 同一个部门的信息存储了多份, 需要占用更多的磁盘空间; 数据冗余有时候也可能是在不同的表中存储了重复的数据, 比如最开始的那个关于购买商品的栗子;
  • 插入异常: 如果想要成立一个新的部门, 由于还没有增加新的员工, 因此无法录入这个部门的信息;
  • 删除异常: 如果某个部门的所有员工都被删除, 该部门的信息也将不复存在;
  • 更新异常: 如果需要修改部门信息, 那么会需要更新多行数据, 效率低下; 不小心忽略了某些记录的话,将会导致数据不一致;

为了解决这些问题,数据库引入了规范化过程。而规范化便使用我们上面说的"范式"来定义和衡量。关系模式的创始人 Edgar Codd 最早提出了第一范式(1NF)、第二范式(2NF)以及第三范式(3NF)。随后又出现了更高级别的范式,包括 BC 范式(BCNF)、第四范式(4NF)等。每个范式都基于前面的范式,例如第二范式需要先满足第一范式。它们之间的关系如下图所示:

技术图片

下面我们对范式进行具体的分析,对于大多数的数据库系统而言,到达第三范式就已经足够了。

第一范式:

第一范式要求满足以下条件:

  • 表中的字段都是不可再分的单一属性;
  • 表需要定义主键(PRIMARY KEY);

简单来说,首先就是每个属性要有单独的字段。在上面的不规范设计中,员工的居住地址和手机号都存储在一个字段中,破坏了原子性。另外,还需要为表定义一个主键,用于唯一识别表中的每一行数据;假设每个部门中的员工不会同名,可以使用部门名称加员工姓名作为联合主键。

将上面的示例修改成以下结构就可以满足第一范式:

技术图片

这里我们将原来的"居住信息"拆分成了两个字段,因为员工的手机号和住址是相互独立的;此外我们将"部门名称"和"姓名"作为了联合主键(假设不重复),当然更常见的做法是使用数据库的自增主键。

第二范式:

第二范式要求满足以下条件:

  • 满足第一范式;
  • 非主键字段必须完全依赖于主键, 不能只依赖于主键的一部分(不能存在部分函数依赖);

A和B能够确定C,但是单独的A或B不能确定C,此时C完全依赖于(A, B);A和B能够确定C,但是单独的A或B也能确定C,那么C部分依赖于(A, B)。而在第二范式中,非主键字段必须要完全依赖于主键。

示例中的"部门地址"只取决于"部门名称"、也就是主键的一部分,它和"姓名无关",因此出现了部分函数依赖。显然,此时部门信息存在冗余,可能带来各种操作异常。

此时,可以将部门信息和职位信息存储到别的表中,并通过外键让它们和员工表之间建立一对多的关系。我们可以继续将表的结构修改如下:

技术图片

第三范式:

第三范式要求满足以下条件:

  • 满足第二范式;
  • 属性不依赖于其它的非主键属性(不能存在传递函数依赖);

怎么理解呢?如果通过A能够确定B,通过B能够确定C,但是通过C不能确定A,那么C的传递依赖于A。

对于前三个范式而言,只需要将不同的实体/对象单独存储到一张表中,并且通过外键建立它们之间的联系即可满足。

此时,我们再来看看非规范化设计时的几个问题,会发现都得到了解决:

  • 部门、员工以及职位信息分别存储一份,通过外键保持它们之间的联系。因此,不存在数据冗余的问题
  • 如果想要成立一个新的部门,直接录入部门信息即可,解决了插入异常的问题
  • 如果某个部门的所有员工都被删除,该部门的信息不会受到影响,不存在删除异常
  • 如果需要修改部门信息,直接更新部门表即可,不会导致数据不一致

很多不搞大数据的公司可能要求在设计表的时候,必须严格符合第三范式,但是搞大数据的话,其实是不需要遵循第三范式的。因为搞大数据重点是在数仓的建设,分好层才是最重要的,另外如果在数仓建设中严格遵循第三范式的话,那么需要很多的外键,而为了维护外键需要额外的性能。但如果不用外键的话,在查询的时候就又会出现大量的join。

关系建模和维度建模

当今的数据处理可以分为两大类:联机事务处理(OLTP, on-line transaction processing)和联机分析处理(OLAP, on-line analytical processing)。OLTP是传统的关系型数据库的主要应用,主要进行基本的、日常的事务处理,比如银行交易;OLAP是数仓系统的主要应用,支持复杂的分析操作,侧重决策支持,并且提供直观易懂的查询结果。

技术图片

把OLTP想象成PostgreSQL,OLAP想象成Hive即可。一般搭建数据仓库,所面临的场景都是数据量达到关系型数据库不好存储了(当然即便数据量不大,也是可以使用数仓的,把关系型数据库本身当成数仓也行),而且对于数仓来说,它的重点在于大批量数据查询分析,不在于数据的导入。所以OLAP不可能像OLTP那样,来一条数据就插入一条,而是要批量导入的。另外Hive的底层存储使用的HDFS,从HDFS的设计原理来讲,我们也能看出它不适合少量数据的频繁导入,而是一次性导入大批量数据。

关系建模:

关系模型是要遵循第三范式的,通过拆分成多个物理表,来降低数据的冗余度。由于数据分布在众多的表中,这些数据可以更加灵活的背应用,功能性更强。关系模型主要应用在OLTP系统中,为了保证数据的一致性以及避免数据冗余,所以大部分业务系统的表都是遵循第三范式的。

维度建模:

维度模型不需要遵循第三范式,它主要应用于OLAP系统中,通常是以某一个事实表为中心进行表的组织,主要面向业务。特征是存在数据冗余,但是能最方便地得到数据。

关系模型虽然数据冗余度低,但是在大规模数据的跨表分析和统计查询的过程中,会造成多表关联,会导致执行效率的大幅度降低。而数仓主要在于查询,所以我们会采用维度建模,把相关的表分为两种:维度表和事实表。

而在维度建模的基础上又分为三种模型:星型模型、雪花模型、星座模型。

星型模型:

技术图片

事实表周围便是维度表(关于两者的区别后面会说),星型模型要求"事实表"周围的"维度表"只能有一层。

雪花模型:

技术图片

雪花模型的话,事实表周围的维度表可以有多层。可以看到雪花模型比较靠近第三范式,但是无法完全遵守。因为对于数仓建设来说,完全遵守第三范式的成本太高,原因就在于join。

星座模型:

星座模型和前两个模型的区别就在于事实表的数量,星座模型基于多个事实表,显然这才是数仓的常态。因为数仓肯定不只有一个事实表,并且维度表是可以被多个事实表共享的。比如上图:图中的事实表可以认为是员工参与辩论赛的一张表,有比赛等级(省级、市级、县级等等),论文标题,参与身份(一个团队参赛、该员工扮演的角色)。而它周围的维表显然是员工的一些个人信息,这些个人信息显然还会被其它的表所需要,因此很好理解。

模型选择:

模型有以上三种,那么实际建设中要选择哪一种呢?

首先星座模型只跟数据和需求有关系,跟设计无关,这个不用选择。如果维度表被多个事实表需要,那么就是星座模型;否则就不是星座模型,但是绝大部分都是星座模型,因为不可能就只有一张事实表。所以我们看到星座模型和剩余两种模型之间是不冲突的,要么是星座模型+星型模型,要么是星座模型+雪花模型。

因此我们的重心是在星型模型和雪花模型的选择上,至于这两种模型选择哪种,则取决于性能优先,还是灵活优先。

目前实际企业开发中,不会绝对选择一种,而是根据情况灵活组合,甚至并存。但是从整体来看,更倾向维度更少的星型模型。尤其是Hadoop体系,减少join就是减少shuffle,而shuffle是一个性能非常低下的操作。而很多公司用的也正是Hadoop体系,比如Hive,本质上是对MapReduce进行了封装。

另外,OLAP大部分都是基于Hive、Spark,但是实际上还有很多其它更加优秀的框架,比如:kylin、presto等等,它们的表现更加优秀,只不过Hive、Spark出现的要早一些。但是,大人食大便啦。

Apache Kylin是一个开源的、分布式的分析型数据仓库,提供Hadoop/Spark 之上的 SQL 查询接口及多维分析(OLAP)能力以支持超大规模数据,最初由 eBay 开发并贡献至开源社区。它能在亚秒内查询巨大的表。

而Presto是由 Facebook 推出的一个基于Java(就很烦)开发的开源分布式SQL查询引擎,适用于交互式分析查询,数据量支持GB到PB字节。

我们有机会慢慢介绍。

维度表和事实表

维度表

维度表:一般是对事实的描述信息,每一张维度表对应现实世界中的一个对象或者概念。例如:用户、商品名、日期、地区等等,所以维度表描述是静态信息。

维度表的特征:

  • 维表是一张宽表(具有多个属性、列比较多)
  • 跟事实表相比,行数相对较小,通常小于10万条。比如公司的人员信息表就是一张维度表,显然公司很少会超过10万人。
  • 内容相对固定,不是很容易变,因为是静态信息。比如人员表,存储人员的姓名、年龄、工号、手机号等等;比如商品表,存放商品的名称、价格、描述、功能等等。这些信息基本上是固定的,当然不是一直不变,而是变化频率很低。再比如时间表,我们为了避免计算,可能把某个日期是星期几、一年当中的第几天、一年当中的第几周、哪个季度、是否是周六日等等也会存储起来,而这种表一旦导入就不会再更改了。

所以,维度表存储的是那些会被其它表所引用的、不会常变的静态信息。

事实表

事实表:里面的一条数据都代表一个业务事件(下单、支付、退款、评价等等),"事实"这个术语表示的是业务事件的"度量值"(可统计次数、个数、金额等等),所以订单表便是一张事实表。

每一个事实表的行包括:具有度量值、与维表相关联的字段(比如: 通过user_id和用户表关联)

事实表的特征:

  • 非常的大
  • 内容相对的窄(列数较少)
  • 经常会发生变化,每天会新增加很多。

而事实表又分为以下三种:

事务型事实表:以每个事务或者事件为单位,例如一个销售订单记录、一个支付记录,便是事实表中的一行数据;一旦事务被提交,数据进入到事实表中,那么事实表中的数据就不能再修改了,其更新方式为增量更新。

周期型快照事实表:周期型快照事实表不会保留所有数据,只保留固定时间间隔的数据,例如每天或者每月的销售额、账户余额等等。

累计型快照事实表:累计型快照事实表用于跟踪业务事实的变化。例如:订单查询,我们在购买商品的时候,商品邮寄到达了什么地方都会动态更新。显然当这个业务进行时,事实表的记录也要不断更新或者插入。再比如工作中执行任务,当任务下发的时候,任务状态为"任务下发";当员工接收任务时,任务状态为"任务处理中";当员工完成任务之后上报时,任务状态为"任务已完成"。所以累计型快照事实表它负责跟踪一个业务的整个生命周期,每当状态发生更改,就会修改表记录、或者新增一条记录。

数据仓库建模

ODS层

  • 1. 保持数据原貌, 不做任何修改, 只起到备份的作用;
  • 2. 数据采用压缩, 减少磁盘使用;
  • 3. 创建分区表, 每一天的数据是一个单独的文件夹, 防止后续使用where进行全表扫描;

DWD层

DWD层算是数仓中最重要的一层了,需要构建维度模型。一般采用星型模型,呈现的状态一般为星座模型。

而维度建模一般采用以下四个步骤:选择业务过程、声明粒度、确认维度、确认事实。

1. 选择业务过程

在业务系统中,挑选我们后续需要关注的业务线,比如:下单业务、支付业务、退款业务、物流业务等等,一条业务线对应一张事实表。

2. 声明粒度

数据粒度指数据仓库中保存的数据的细化程度或者综合程度的级别。

声明粒度意味着精确定义事实表中的一行数据表示什么,应该尽可能选择最小粒度,依次来满足各种各样的需求。

比如:

  • 订单事实表中每个商品项作为一行数据, 那么粒度就是"每次下单";
  • 每周的订单次数作为一行, 粒度就是"每周下单";
  • 每月的订单次数作为一行, 粒度就是"每月下单";

3. 确定维度

维度的主要作用是描述业务,主要表示"谁、何处、何时"等信息。

4. 确定事实

此处的"事实"一词,指的是业务中的度量值,例如订单金额、下单次数等等。

在DWD层,以"业务驱动"为建模驱动,基于每个具体业务过程的特点,构建最细粒度的明细层事实表,必要情况下可适当宽表化。

还是以电商为例:

技术图片

横坐标是维度,纵坐标是事实表,不同的事实表会依赖同一张维度表。

至此数仓的建模已经完毕,DWS、DWT、ADS和维度建模已经没有关系了。

而DWS、DWT都是建宽表,而建宽表则按照主题去建,主题相当于观察问题的角度,对应着维度表。比如:图中有八张事实表,我想查看哪些商品被加入到购物车里面了、哪些商品被评价了、哪些商品被退款了等等,这里的商品便是主题。

DWS层

统计各个主题对象的当天行为,服务于DWT层的主题宽表,以及一些业务明细数据,应对特殊需求(例如:购买行为,统计商品复购率)。

DWT层

以分析的主题对象为建模驱动,基于上层应用和产品的指标需求,构建主题对象的全量宽表。

ADS层

对各大主题指标分别进行分析。

2. 数仓理论

标签:冗余   基于   职位   组合   原因   避免   shu   设计   交互   

原文地址:https://www.cnblogs.com/traditional/p/13549770.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!