在数据同步任务开发过程中,有一个问题经常会被问到:全量OR增量?处了部分业务场景特殊要求外,一般还是按照上游数据更新方式来进行同步。在数据更新过程中,有一个比较重要的概念:缓慢变化维(Slowly Changing Dimension)
SCD问题简单介绍
在数据仓库的数据模型设计过程中,经常会遇到下面这种表的设计:
有一些表的数据量很大,比如一张合同表,大约5000万条记录,289个字段。表中的部分字段会被update更新操作,如客户基本信息,产品的描述信息,合同的状态等等。需要查看某一个时间点或者时间段的历史快照信息,比如,查看某一个合同在历史某一个时间点的状态。表中的记录变化的比例和频率不是很大,比如,总共有10亿的用户,每天新增和发生变化的有200万左右,变化的比例占的很小。
维度缓慢变化维SCD(Slowly Changing Dimensions)一些维度表的数据不是静态的,而是会随着时间而缓慢地变化(这里的缓慢是相对事实表而言,事实表数据变化的速度比维度表快)把处理维度表数据历史变化的问题,称为缓慢变化维问题,简称SCD问题。
例如:根据合同类型的维度,统计不同的合同类型在某一时间段的发货占比。而期间,用户可能去修改某一个合同的合同类型,例如:将测试合同改为客户需求合同。此时,合同维度表就发生了变化。当然这个变化相对事实表的变换要慢。但这个维度表的变化,就是缓慢变化维。
那么对于这种表该如何设计呢?下面有几种方案可选:
-
方案一:每天只留最新的一份,比如我们每天用DATASTAGE抽取最新的一份全量数据到GaussDB中。
-
方案二:每天保留一份全量的切片数据。
-
方案三:使用拉链表。
SCD问题的几种解决方案:
重写维度值
修改维度属性为最新值,直接覆盖,不保留历史信息。
比如合同属于哪个类别:当合同类别发生变化时,直接重写为新类别,如果业务只关心最新的类别。
插入新的维度行
在维度表中增加新的一行,新行中采用新的属性值。此种方式需要借助代理键,需要为新行分配新的代理键,将其作为事实表的外键。
采用此方式,一般会在维度行中额外增加3列:行生效时间,行失效时间以及当前行标识(或者不使用当前行标识,由行失效时间来判断是否是当前行)
此方式及其变种是处理缓慢变化维的主要技术。
维度属性值变化前:
合同号 | 合同类型 | 行生效时间 | 行失效时间 | SCD_ACTIVE_IND |
---|---|---|---|---|
001A | 测试合同 | 2020-01-01 | 9999-12-31 | 1 |
维度属性值变化后:
合同号 | 合同类型 | 行生效时间 | 行失效时间 | SCD_ACTIVE_IND |
---|---|---|---|---|
001A | 测试合同 | 2020-01-01 | 2020-01-31 | 0 |
001A | 技术服务合同 | 2020-02-01 | 9999-12-31 | 1 |
添加维度列
在维度表中增加新的一列,原先属性列存放上一版本的属性值,当前属性列存放当前版本的属性值。
维度属性值变化前:
合同号 | 合同类型 | 其他属性 |
---|---|---|
001A | 测试合同 | XXX |
维度属性值变化后:
合同号 | 当前合同类型 | 原合同类型 | 其他属性 |
---|---|---|---|
001A | 技术服务合同 | 测试合同 | XXX |
快照维度
此种方式比较暴力,每天保留全量维度属性的快照数据。
此方式依托的是当前存储成本远低于计算成本,以空间换时间的理念。
跑数日期 | 合同号 | 合同类型 | 其他属性 |
---|---|---|---|
20200101 | 001A | 测试合同 | XXX |
20200101 | 002A | 客户需求 | XXX |
20200102 | 001A | 技术服务合同 | XXX |
20200102 | 002A | 客户需求 | XXX |
20200103 | 001A | 技术服务合同 | XXX |
20200103 | 002A | 客户需求 | XXX |