DWH的保留原始历史数据的一种方法

前几天有朋友咨询在数据仓库Stage或ODS层该如何保存历史数据, 他的这个问题其实很普遍, 所以写了点东西放在博客上.

一般数据仓库项目中, Stage或ODS层要保留几天或几个月的源表数据. 保留历史业务数据是很必要的, 有时候需要DWH重跑某一天的数据, 这种情况下, 无法从前端OLTP系统取的当时的数据. 在比如, 需要DWH在一天内要回跑多天batch, 这在项目刚上线时经常碰到.

至于是在Stage层还是ODS层保留历史数据, 我一般推荐是在Stage层保留历史, 让ODS只保留当天的快照数据.  因为Stage保留的是最原始的数据.

那如何保留一个表(比如TA表)的历史数据呢? 我能想到的做法有:
1. 将多天的数据都放在一个表, 加上一个batch_id字段来区分到底是哪天的数据.
2. 用不同表名保存, 比如TA_20110509, TA_20110510 等等.
3. 表名相同, 但把表放在不同的schema下, 比如B20110509.TA, B20110510.TA

这3种做法各有优缺点:
方法1的优点是, 实现起来简单, 缺点也很明显, 就是效率会很差, 如果TA是个大表, 更是如此.
方法2的优点是, 和方法1比, 查询和操作数据的效率要好, 缺点是, 编程会复杂一些, 尤其是使用ETL工具, 你可能使用变量或者其他手段将表名传给ETL Job.
方法3的优缺点和方法2基本相同, 另外的优点是,数据库backup管理的粒度能做的很细. 另外一个缺点是, 需要管理多个schema的权限, 会繁琐一些.

我推荐采用方法2. 上面讲了方法2比方法1会复杂一些, 有没有相对简单的实现方式呢? 下面是我给的一个思路和实现方法.

思路, 假设TA表, 需要保存7份, 分别保存在TA_0, TA_1, TA_2, ..., TA_6表中, 第一次保存到TA_0表, 以此类推, 第7次保存到TA_6表, 第8次再重新使用TA_0表. 我们可以动态生成两个视图, V_TA和V_TA_LAST,. V_TA视图指向当前batch的工作表,V_TA_LAST指向上一个batch的工作表. 另外, V_TA视图是属于那种可更新的视图, 所以可以在ETL Job(或ETL SP)中V_TA, 而不需直接用TA_0或其他表.

实现:
实际项目中, 不同表保存的份数可能不同, 另外需求可能在项目实施过程中, 也有变化, 所以最好是做成可配置模式. 下面给出2个表, Table_Version_Control_Static定义了各个表的版本控制规则, Table_Version_Control_History记录各表版本控制历史.

上面讲过, TA表如果需要保存7份, 分别保存在TA_0, TA_1, TA_2, ..., TA_6表中, 第一次保存到TA_0表, 以此类推, 第7次保存到TA_6表, 第8次再重新使用TA_0表, 这个过程有点像时钟, 周而复始, 如下图.


可写成一个存储过程sp_clock_go_ahead(n)来完成这个时钟旋转过程. 具体讲,该存储过程依次完成如下工作:
 1. 动态创建TA_n, 如果TA_n不存在的话.
 2. 修改V_TA视图, 让它指向TA_n.
 3. 修改V_TA_LAST视图, 让它指向TA_n-1

虽然V_TA视图是可更新的,但不支持truncate操作, 所以可以写一个简单的sp(比如sp_Truncate_Table)来完成truncate操作.

有了上面的2个表和2个存储过程, 不管是全量刷新表还是增量刷新表, 都很简单, 步骤见下:
一. 如采用增量刷新(Incremental), 刷新的步骤是:
 1. 执行sp_Clock_Go_Ahead()
 2. 如果Save_Points>1, 原样复制V_TA_LAST至V_TA, 结果是V_TA和V_TA_LAST记录数一致
 3. Delta Load 到 V_TA

二. 如采用全量刷新(Full), 刷新的步骤是:
 1. 执行sp_Clock_Go_Ahead()
 2. 执行sp_Truncate_Table() ,来truncate 表TA_n
 3. Load data 到 V_TA

原文地址:https://www.cnblogs.com/harrychinese/p/DWH_Stage_History_Store.html