数据仓库基础
基本组件
star schema:维度数据仓库的数据库结构
surrogate key:数据仓库表里作为主键的列
除了star schema,也有在数据仓库中用snowflake schema的,不过后者更难建模、不容易理解和实现、性能较前者差
维度数据仓库包括两种类型的关系数据库表:fact表和dimension表
一个fact表+周围多个dimension表就是一个star结构,multi-start结构则有多个fact表,其中多个fact表共享一些共用的dimension表
fact表一般后缀为fact,而dimension表后缀为dim
fact表包含多个可度量的事实,可度量的事实成为measure,dimension表对measure进行分类
每个dimension表包含一个surrogate key列,列名后缀为sk,dimension里每个sk列在fact表都有一个类似的列
dimension表里的sk列是主键,一般sk的值为顺序的数字且不含业务含义
Dimension历史
dimension会随着时间而改变,比如用户会更改地址、产品改名或重新分类、销售订单修正等等
我们必须维护dimension的历史,这样才能保证就的销售订单指向旧的产品分类,而新的销售订单指向新的产品分类
Slowly Changing Dimension(SCD)是维度数据仓库里实现dimension历史的技术
SCD包含三种类型:
- SCD1:总是用新的数据覆盖老的数据,不保存历史
- SCD2:总是创建新版本的dimension,不修改和删除老的数据
- SCD3:保存有限的dimension历史,如对customer_address列维护一个previous_customer_address列
Measure Additivity
Measure的一个重要特质是Measure Additivity
如果一个measure在所有情况下都可以sum,那么称这个measure是fully-addative
如果一个measure只能在某些情况下做sum,那么称这个measure是semi-addative
也就是说,如果一个measure在任意一个dimension上计算的总和与任意其他一个dimension上计算的总、其他dimension任意组合上计算的总和都相等,那么这个measure就是fully additive的
维度查询
维度查询包括三个常见类型:
- aggregation:对fact进行求和
- specific:对特定的dimension值进行fact查询和求和
- inside out:基于fact的measure值条件进行查询
ETL
源数据提取
有两种源数据提取方式:
- Whole Source:提取整个源数据,这种模式对参考性质的数据源比较合适,如邮政编码
- Change Data Capture(CDC):只提取增量改动的数据,如果数据源特别大而且提取整个数据效率低时适用,通常作为动态数据源的提取方式
提取数据时可以采用Pull后Push两种方式
组装Date Dimension
在数据仓库里时间维度是最重要的,因为数据仓库的首要功能就是存储历史数据,所以数据仓库里始终有时间维度
三种常见的组装date dimension的技术:
- 提前组装:比如提前准备好十年内所有的date dimension
- 每天一个date:每天准备一条新的date记录
- 从源数据加载date:从源数据加载仅仅被使用的date
初始化组装
在开始数据仓库操作之前的第一步就是加载历史数据
最好有一个Source Data到Data Warehouse的映射文档来列出需要哪些数据源、数据格式已经对应的fact/dimension表,然后写初始化脚本来加载数据
定期组装
和初始化组装一样,最好有一个文档来列出源数据、数据仓库表、提取模式(Whole/CDC、Push/Pull)、加载类型(SCD、Pre-populate)等等,然后写加载数据的脚本
定期组装调度
Windows控制面板里添加任务向导或者Linux下crontab程序都可以添加定时调度任务
演进
添加列
数据仓库常见的需求是添加列到已有的dimension和fact表
更改dimension和fact表之后需要修改定期组装脚本
按需组装
有时候在定期组装之外需要一些按需组装,比如促销销售的源数据只有在促销阶段才有
这时通常需要dimension、fact表的更改和一些按需组装的脚本
Dimension子集
由于有些用户不会使用所有的dimension数据,比如用户只关心month,不关心date,所以我们可以提供一个month_dim(date_dim的子集)
Dimension角色扮演
有时候一个fact需要使用同一个dimension多次,比如销售订单fact需要两个date,一个是下订单时间一个是发送订单时间,这时可以用dimension角色扮演技术来实现。
有两种dimension角色扮演的类型:表别名和数据库视图
表别名就是指在查询时对同一个表取多个不同的别名来区分,以满足查询多次同一个dimension的目的
数据库视图就是对已有的dimension根据使用次数建多个视图来满足多次使用同一dimension的目的
快照
有些用户可能只需要特定时间的数据,换句话说,他们只需要数据的快照
有两种类型的数据快照:周期性快照和累积性快照
周期性快照是fact在一定周期内的sum总和,如monthly fact表在每个月结束时会有一个快照
累积性快照跟踪fact的更改,如销售订单的持续累积数据
Dimension Hierarchy
大部分dimension有一个或多个层次结构,如date dimension有一个分4级的层次结构:year级别、quarter级别、month级别和date级别,而且只有year-quarter-month-date这一条单一路径
同一主题下的列可以归为一组,而且组的成员至少包含另一个成员,如果month包含date,这时就会形成一个层次结构,比如year-quarter-month-date是date dimension的一个Hierarchy
在Hierarchy上可以做grouping和drilling
grouping查询会对fact按dimension做group by,但是只显示到最低级别的数据,而drilling则是显示dimension各种级别的数据
多路径Hierarchy和不平整Hierarchy
有时候一个Hierarchy会有多条路径,比如year-quarter-month或year-campaign-month,所以查询时可以按不同的路径进行drilling
Hierarchy中如果不包含一个或多个级别的数据,那么称之为不平整(Ragged) Hierarchy,例如某几个month没有campaign session,那么month dimension被称为ragged campaign hierarchy
如果某几个month不存在campaign,则用month代替,最终drilling查询结果会将不存在campaign的行用month代替(导致多行相同的month),而有campaign的行的metric值是对应month的metric值的总和
Dimension退化
当用户不需要某部分dimension数据时,可以将dimension退化,移除哪些不用的数据,从而增加查询性能
比如退化order_dim表的步骤:
- 将order_number列加到sales_order_fact表
- 将已有的order_number从order_dim移到sales_order_fact表
- 从sales_order_fact表中移除order_sk列
- 移除order_dim表
Junk Dimension
有些dimension字段的值的种类特别少,比如只有yes和no两种值的一些字段,它们应该放在称为junk dimension的dimension表里
Multi-Star Schema
如果数据仓库里有多个fact表,则应称之为Multi-Star Schema
高级技术
非直接的数据源
如果数据源由于粒度不同不能直接加载到数据仓库,则需要ETL时做一些转换
无事实的fact表
有时候需要度量一些源数据里没有的数据,比如产品计数,我们可以建立一个无事实的fact表来实现
延迟fact
有时候fact表的数据有延迟,导致快照fact表的数据不对,这时需要改进定期fact组装脚本来处理这种延迟数据
合并Dimension
随着数据仓库有些dimension表有重复的数据,我们可以将它们合并到一个单独的dimension
累积度量
有时候需要跟踪一些累积的度量,比如month-end balance,这时就需要增加额外的measure,并且在加载数据时注意加上之前的值
范围Dimension
一些连续的值的范围构成范围(band) dimension,比如销售订单的数量0.01-15000为”LOW”,15000.01-30000.00为”MED”,30000.01-99999999.99为”HIGH”
这时可以为这个dimension单独见一个band dimension表,然后fact表添加sk即可