数仓分层
数仓简介
1. 数据仓库和数据库的区别
数据仓库:
数据量特别的大,TB~PB 级别
会保留历史数据
一般使用 OLAP 分析(On-Line Analytical Processing),联机分析处理(聚合操作),多维分析
会有重复的数据
数据库:
数据量:GB~TB
不保留历史数据
一般使用 OLTP(On-Line Transaction Processing),联机事物处理(增删改查)
传统的数据
2. 如何创建数据仓库?
数据仓库的创建一般关注两个方面,一是如何创建仓库中的表,这个是指如何维护仓库中的表,即全量、增量、增量和变化等;二是如何对数据进行分层,这个指通过分层操作来减少对表中数据的重复查询。
3. 数据仓库分层
一般数据仓库分为 ODS 层、DW 层、ADS 层,其中 ODS 层是对原始数据的备份,DW 层是对数仓的建立,其中又分为 DWD 层和 DWS/DWT 层,ADS 层是对指标的最终分析。每一层的含义如下:
ODS 层:Operation Data Store,存放原始数据,将 HDFS 上的数据原封不动的存储到 ODS 层,起到数据备份的作用。
DWD 层:Data Warehouse Detail,明细数据层,对 ODS 层的数据进行清洗,如去除空值、脏数据、脱敏(用于保护用户的隐私)、维度退化等。
DWS 层:Data Warehouse Service,数据服务层,以 DWD 为基础,按天统计,进行轻度的汇总。
DWT 层:Data Warehouse Topic,数据主题层,以 DWS 层为基础,按主题进行汇总。
ADS 层:Application Data Service,数据应用层,以 DWT 为基础,为各种报表提供数据。
4. 数仓为什么要进行分层:
将复杂的问题简单化
复杂任务分解成多层来实现
每一层处理一些简单的任务
方便定位问题
减少重复开发
中间层的数据,可以重复利用到不同的需求
如果计算出错,不需要重头开始计算
隔离原始数据
数据集市
数据集市是数据仓库的下游,是对数据仓库的进一步划分,各个数据源中的数据进入数据仓库后,按照不同业务需求类型对数据的进一步分类。如果把数据仓库比作一个企业,那么数据集市就是面向企业中的一个个部门,然后计算某个指标时就从相应的集市中取。
数仓理论
关系建模
关系建模就是针对数据库中表的建立采用的方式,一般指的是关系型数据库建模,这种方式要遵守一定的规范要求,其目的在于降低数据的冗余。数据冗余指在不同或相同的表中存在重复数据,这样必然会造成数据存储量的增加,在早期 2000 年时,磁盘的价格很贵,另外那时都是单机系统,如果数据量增加只能通过增加磁盘的方式进行扩容,那么成本必然增加,所以必须要降低数据的冗余。
但是关系型数据库有个很大的缺点,因降低了数据的冗余,数据的耦合性低,大多数结果都是通过多表 join 拼接得到,那么修改一个数据时,需要修改关联的多个表,这样很难保证数据的一致性。
因此,关系型数据库数据较为松散、零碎,物理表数量多,数据冗余度低。
下面来说下数据建模要遵守的规范。
范式理论
在学习范式理论之前,先说说函数的依赖,因为范式理论和函数的依赖有关系。
函数的依赖
完全函数依赖:z = f(x,y) = x + y,结果 z 完全依赖于 x 和 y,缺一不可。
部分函数依赖:z = f(x,y) = x + 2,结果 z 只依赖于 x,即部分依赖。
传递函数依赖:z = f(x),z = f(y),结果 z 依赖于 y 值,y 值依赖于 x,但 z 不直接依赖于 x,即传递依赖。
以上依赖在数据库中是以主键字段和普通字段体现的,在完全函数依赖中,如学号 + 学科是主键,那么分数就完全依赖于主键学号 + 学科;在部分函数依赖中,如学号 + 学科是主键,那么学生姓名依赖于主键学号即可,不需要主键学科,即依赖了部分主键;在传递函数依赖中,如学号是主键,那么通过主键学号可以找到所在班级 id,通过班级 id 可以找到班主任,即班主任传递依赖于主键学号。
范式理论
范式分类:
目前业界范式有:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)、第五范式(5NF)。
在行业内,目前大都是遵守三范式:
- 第一范式:属性不可切割,比如一个时间字段,格式为年-月-日,但如果需要字段年、字段月、字段日,那么就要对原时间字段进行切分成三个字段。
- 第二范式:不能出现部分函数依赖,注意针对的是联合主键,每一列都要和联合主键相关,而不是单一主键(可只有单一主键)通过分表的方式,最好是去除部分依赖,不要建立联合主键,可以有联合索引。
- 第三范式:不能出现传递函数依赖,每一列都要直接和主键相关,不能间接相关。
- 巴斯-科德范式:针对联合主键之间,主键决定主键的情况,任一主键唯一关联另一主键,这样不允许。
范式主要是为了避免数据的冗余,但范式越多分出的表就越多,范式只是一个标准。有的时候需要数据的冗余,因为分表多意味着关联查询,在 HDFS 中关联查询意味着 shuffle,这是严重影响效率的,所以要适当冗余。
关系建模与维度建模
建模就是创建表,关系建模和维度建模的区别如下。
关系建模:主要是常规数据库的建表方式,降低数据的冗余,如 MySQL。
关系建模依赖于范式原理(主要是三范式)设计原则
侧重数据的事务性
一张表的数据达到了 500G 以上以后,效率比较低
维度建模:存在数据的冗余。
按照维度建模的思想进行设计表
多角度进行分析
表结构是:中间一个事实表,周围是维度表
数仓主要是维度建模,下面我们说下维度建模。
维度建模
1. 维度建模的模型分类:
- 星型模型:一张事实表,多个一层维度表
- 雪花模型:一张事实表,多个多层维度表,比较靠近第三范式
- 星座模型:基于多个事实表,多个事实表之间有共同的维度表
2. 维度建模模型的选择:
- 原则:取决于性能更优还是灵活更优。星型模型性能更优,雪花模型灵活更优。
- 选择:当前是更倾向于维度更少的模型,尤其是在 Hadoop 的体系中,减少 join 就是减少 shuffle。
关系型数据库可以依靠强大的主键来优化效率。
3. 维度建模的优势:
表结构清晰,容易上手
存在数据的冗余,查询速度快
使用于多维分析
4. 不同模型的区别:
雪花模型就是对星形模型的维表做进一步的拆分,形成下一层的维表,星座模型是共同的维表关联多个事实表。在数仓建立中,一般就是使用星形模型,因雪花模型意味着维表更多,即关联更多产生 shuffle 更多,当然多个星形模型的建立也必然会形成星座模型的出现。
事实表和维度表
一定要理解好事实表和维度表,数仓中的表会大量针对这两种类型的表进行分析,理解好这两种表的含义,才能对数仓建设的更加合理完善。
简介
如何理解维度表和事实表?
事实表:根据业务来的,一个业务建成事实表。如电商中的收藏、评论、加购物车、下单、支付、领用优惠券、退款等业务,都可以成为一张事实表,即记录的是具体的业务行为。
维度表:对事实表的描述信息。如时间、地点、用户、商品、活动、优惠券等维度表,是对事实表特征的描述,注意,一般事实表中用外键 id 关联的表基本都是维度表。
维度表和事实表在数仓的不同层中的维护是不一样的,一定要注意当前处理的是数仓中的哪一层,然后对不同层的维度表和事实表采用相应的更新策略。
维度表
1. 维度表是为事实表服务
2. 特征:
维度表的范围很宽,具有多个属性,列比较宽
与事实表比,行数比较少,<10 万条
内容相对比较固定:如编码表、地区表
事实表
1. 事实表中的每行数据代表一个业务事件,如下单操作、支付、退款、评价等
2. 特征:
数据量大
内容相对窄,列数量较少,行数量很大
经常性变化,每天都会有新增很多数据
3. 结构:
由度量值字段(1 个及以上) + 与维度表关联的外键字段(2 个及以上) + 冗余字段
4. 度量值
即表中衡量具体量的值,大部分为数值,也可以用文字表示,度量值要在维度字段配合下才有意义,可以分为三种类型:
- 可加:使用任意维度均可加。这里“可加”可理解成 SQL 中的 group by。
- 半可加:该度量值只能在某些维度可加。如:地点维度可以加,但是在时间维度没意义。
- 不可加:在任何的维度都不可加。例如:比率 10%、20%,每个比率都是多个普通度量计算后的值,即有分子和分母,不能对比值后的结果进行加操作,可以将这种比率度量进行拆分,分子和分母分别进行加操作后,再得到比率,即为比例的加操作了。
事实表的分类
事实表的分类:事实表和业务有关,所以分类也是根据业务类型来分的。
1. 事务型事实表:历史数据不会改变,如学生答题记录。
数据更新方式:增量更新,只增加新的数据,不会对旧的数据类型进行更改,因历史数据不会改变。
应用场景:只有新增的数据,旧数据不会变更的事实表采用这种类型。
2. 周期性快照事实表:不关心过程,只要最后的结果数据,如学生收藏点赞情况。
数据更新方式:全量,每天一个快照。
应用场景:只关心最终的一个结果,不关心中间的业务操作过程,比如加购表,上午加了一个产品到购物车中,下午又将这个产品从购物车删除,我们不关心这个过程,只关心这一天中加购表中的最后数据。
3. 累积性快照事实表:这个业务需要好几个过程才能完成,每次记录中间一个过程,如学生一门课的学习过程。
数据更新方式:新增及变化。
应用场景:一条数据一次写不完,需要多次才能写完,如学生学习表,既有新增加的课程学习数据,又有对已学课程的状态变化,如开始学习,学习中,已学完等。
数据仓库建模
注意,我们常说的数据仓库建设,其实主要是指 DWD 层的建设。每一层的数据都包含两部分,一是埋点的 JSON 格式的数据,二是 MySQL 等数据库中的业务数据,这两种数据的同步和维护策略都是不通的。
ODS 层
1. 说明:
数据和 HDFS 上数据保持一致,不做任何的修改,起到数据备份作用。
数据采用 LZO 压缩,需要索引文件,MySQL 导入 HDFS 时,自带索引文件,log 文件不带索引文件,所以在 ODS 层需要自己加索引。
创建分区表,一般以天为单位。
同步策略与 MySQL 和 log 数据存储到 HDFS 的同步策略保持一致。
2. 原始数据的同步
log 文件:即打点或埋点数据。
每天一个文件夹,Flume 采集以后的数据就直接发送到 HDFS 上
方法:最后一个 Flume 的配置文件中,将每天的数据放进一个当天日期的文件夹中
压缩:文件夹中的数据采用 LZO 压缩,同时没有索引文件
每个文件夹中的数据:当天产生的日志数据
DB 业务数据:
对于 MySQL 中的每一张表,每天导一次,数据就会创建一个 LZO 压缩 + LZO 索引的文件夹,注意同步策略不包含特殊表,如省份表、地区表
同一张表,每天导的数据会进入当天的文件夹,使用 Sqoop
当天的文件中存储的数据是什么?
通过 Sqoop 将 MySQL 导入到 HDFS 中,根据同步策略的不同,当天文件夹中存储的数据不同,具体如下:
全量同步策略:MySQL 中所有的数据。
新增及变化策略:今天 MySQL 中新增和变化了的全部数据。
新增同步策略:今天 MySQL 新增的全部数据 。
每张表的同步策略中,还要区分数据量的多少,如果是数据量小,那么可以全量更新,如果数据不会再变化,那么统一一次即可,如地区表,如果数据量很大,那么就要考虑新增或者新增及变化的方式。
3. HDFS 数据同步到 ODS 层
ODS 层的表要建立成分区表,分区单位是天,针对埋点和业务数据,采用不同的同步方式:
埋点数据:创建一个字段为 line,分区字段为 dt,JSON 不做任何处理,直接放到 line 字段中
业务数据:即 DB 数据,字段和 MySQL 的字段保持一致,分区字段为 dt
DWD 层
1. 说明:DWD 层是数仓维度建模最核心的部分,一般是采用星型模型,由于存在多个事实表,其实也就形成了星座模型。
2. 建模的 4 个步骤:选择业务过程 -> 声明粒度 -> 确定维度 -> 确认事实。
选择业务过程: 即确定事实表,每一个业务创建一个事实表。
声明粒度:声明事实表的粒度,按照最小粒度确定事实表。
什么是粒度:是一个形容词,表示表中的一行数据保存数据细化程度或综合程度。
声明粒度的过程:
- 第一步:找到和业务相关的所有表
- 第二步:确定这些相关表每一行的粒度
- 第三步:选择粒度最细的表作为事实表。
怎么算是最细的呢?
外键越多,粒度越细;外键越少,粒度越粗。事实表的维度越多,外键越多。
典型的粒度声明如下:学习表中,每行数据对应一个学生,学习详情表中,每行数据对应一个学生的一个科目,选择粒度最小的那个表就可以通过外键 id 关联到更多的表,在下层建立时使用率更高。
为什么要选择粒度最细的表作为事实表?
事实表存储明细数据,不存储聚合数据,而需求一般都需要对数据进行聚合的运算,这样就可以应对各种需求。
确定维度:确定每一张事实表的维度,即表中的外键
确定事实:指确认度量值,以后按照不同维度做聚合
3. 关于事实表几个原则:
- 每一个业务都需要建一个事实表
- 一个事实表中的粒度要一致
- 度量值的单位要一致
- 使用维度冗余,来减少 join 的次数
- null 值,如果是数值类型的数据,那么使用 0 来代替