一起來聊聊數據庫拉鏈表

本篇文章給大家帶來了關于mysql的相關知識,其中主要介紹了關于數據庫拉鏈表的相關問題,拉鏈表是一種數據模型,主要是針對數據倉庫設計中表存儲數據的方式而定義的,顧名思義,所謂拉鏈,就是記錄歷史,下面一起來看一下,希望對大家有幫助。

一起來聊聊數據庫拉鏈表

推薦學習:mysql

拉鏈表產生背景

在數據倉庫的數據模型設計過程中,經常會遇到這樣的需求:

1、數據量比較大;

2、表中的部分字段會被update,如用戶的地址,產品的描述信息,訂單的狀態等等;

3、需要查看某一個時間點或者時間段的歷史快照信息,比如,查看某一個訂單在歷史某一個時間點的狀態,比如,查看某一個用戶在過去某一段時間內,更新過幾次等等;

4、變化的比例和頻率不是很大,比如,總共有1000萬的會員,每天新增和發生變化的有10萬左右;

5、如果對這邊表每天都保留一份全量,那么每次全量中會保存很多不變的信息,對存儲是極大的浪費;

對于這種表有幾種方案可選:

  • 方案一:每天只留最新的一份,比如我們每天用Sqoop抽取最新的一份全量數據到Hive中。
  • 方案二:每天保留一份全量的切片數據。
  • 方案三:使用拉鏈表。

以上方案對比

方案一

這種方案就不用多說了,實現起來很簡單,每天drop掉前一天的數據,重新抽一份最新的。

優點很明顯,節省空間,一些普通的使用也很方便,不用在選擇表的時候加一個時間分區什么的。

缺點同樣明顯,沒有歷史數據,先翻翻舊賬只能通過其它方式,比如從流水表里面抽。

方案二

每天一份全量的切片是一種比較穩妥的方案,而且歷史數據也在。

缺點就是存儲空間占用量太大太大了,如果對這邊表每天都保留一份全量,那么每次全量中會保存很多不變的信息,對存儲是極大的浪費,這點我感觸還是很深的…

當然我們也可以做一些取舍,比如只保留近一個月的數據?但是,需求是無恥的,數據的生命周期不是我們能完全左右的。

拉鏈表

拉鏈表在使用上基本兼顧了我們的需求。

首先它在空間上做了一個取舍,雖說不像方案一那樣占用量那么小,但是它每日的增量可能只有方案二的千分之一甚至是萬分之一。

其實它能滿足方案二所能滿足的需求,既能獲取最新的數據,也能添加篩選條件也獲取歷史的數據。

所以我們還是很有必要來使用拉鏈表的。

拉鏈表概念

拉鏈表是一種數據模型,主要是針對數據倉庫設計中表存儲數據的方式而定義的,顧名思義,所謂拉鏈,就是記錄歷史。記錄一個事物從開始,一直到當前狀態的所有變化的信息。拉鏈表可以避免按每一天存儲所有記錄造成的海量存儲問題,同時也是處理緩慢變化數據(SCD2)的一種常見方式。

百度百科的解釋:拉鏈表是維護歷史狀態,以及最新狀態數據的一種表,拉鏈表根據拉鏈粒度的不同,實際上相當于快照,只不過做了優化,去除了一部分不變的記錄,通過拉鏈表可以很方便的還原出拉鏈時點的客戶記錄。

拉鏈表算法

1、采集當日全量數據到ND(NowDay當日)表;

2、可從歷史表中取出昨日全量數據存儲到OD(OldDay上日)表;

3、兩個表進行全字段比較,(ND-OD)就是當日新增和變化的數據,也就是當天的增量,用W_I表示;

4、兩個表進行全字段比較,(OD-ND)為狀態到此結束需要封鏈的數據,需要修改END_DATE,用W_U表示;

5、將W_I表的內容全部插入到歷史表中,這些是新增記錄,start_date為當天,而end_date為max值,可以設為’9999-12-31‘;

6、對歷史表進行W_U部份的更新操作,start_date保持不變,而end_date改為當天,也就是關鏈操作,歷史表(OD)和W_U表比較,START_DATE,END_DATE除外,以W_U表為準,兩者交集將其END_DATE改成當日,說明該記錄失效。

拉鏈表示例1

舉個簡單例子,比如有一張訂單表:

6月20號有3條記錄:

訂單創建日期 訂單編號 訂單狀態
2012-06-20 001 創建訂單
2012-06-20 002 創建訂單
2012-06-20 003 支付完成

到6月21日,表中有5條記錄:

訂單創建日期 訂單編號 訂單狀態
2012-06-20 001 創建訂單
2012-06-20 002 創建訂單
2012-06-20 003 支付完成
2012-06-21 004 創建訂單
2012-06-21 005 創建訂單

到6月22日,表中有6條記錄:

訂單創建日期 訂單編號 訂單狀態
2012-06-20 001 創建訂單
2012-06-20 002 創建訂單
2012-06-20 003 支付完成
2012-06-21 004 創建訂單
2012-06-21 005 創建訂單
2012-06-22 006 創建訂單

數據倉庫中對該表的保留方法:

1、只保留一份全量,則數據和6月22日的記錄一樣,如果需要查看6月21日訂單001的狀態,則無法滿足;

2、每天都保留一份全量,則數據倉庫中的該表共有14條記錄,但好多記錄都是重復保存,沒有任務變化,如訂單002,004,數據量大了,會造成很大的存儲浪費;

如果在數據倉庫中設計成歷史拉鏈表保存該表,則會有下面這樣一張表:

訂單創建日期 訂單編號 訂單狀態 dw_bigin_date dw_end_date
2012-06-20 001 創建訂單 2012-06-20 2012-06-20
2012-06-20 001 支付完成 2012-06-21 9999-12-31
2012-06-20 002 創建訂單 2012-06-20 9999-12-31
2012-06-20 003 支付完成 2012-06-20 2012-06-21
2012-06-20 003 已發貨 2012-06-22 9999-12-31
2012-06-21 004 創建訂單 2012-06-21 9999-12-31
2012-06-21 005 創建訂單 2012-06-21 2012-06-21
2012-06-21 005 支付完成 2012-06-22 9999-12-31
2012-06-22 006 創建訂單 2012-06-22 9999-12-31

說明:

1、dw_begin_date表示該條記錄的生命周期開始時間,dw_end_date表示該條記錄的生命周期結束時間;

2、dw_end_date = ‘9999-12-31’表示該條記錄目前處于有效狀態;

3、如果查詢當前所有有效的記錄,則select * from order_his where dw_end_date = ‘9999-12-31’;

4、如果查詢2012-06-21的歷史快照,則select * from order_his where dw_begin_date = ‘2012-06-21’,這條語句會查詢到以下記錄:

訂單創建日期 訂單編號 訂單狀態 dw_bigin_date dw_end_date
2012-06-20 001 支付完成 2012-06-21 9999-12-31
2012-06-20 002 創建訂單 2012-06-20 9999-12-31
2012-06-20 003 支付完成 2012-06-20 2012-06-21
2012-06-21 004 創建訂單 2012-06-21 9999-12-31
2012-06-21 005 創建訂單 2012-06-21 2012-06-21

和源表在6月21日的記錄完全一致:

訂單創建日期 訂單編號 訂單狀態
2012-06-20 001 創建訂單
2012-06-20 002 創建訂單
2012-06-20 003 支付完成
2012-06-21 004 創建訂單
2012-06-21 005 創建訂單

可以看出,這樣的歷史拉鏈表,既能滿足對歷史數據的需求,又能很大程度的節省存儲資源;

拉鏈表示例2:

在歷史表中對人的一生的記錄可能就這樣幾條記錄,避免了按每一天記錄客戶狀態造成的海量存儲的問題:

人名 開始日期 結束日期 狀態
client 19000101 19070901 H在家
client 19070901 19130901 A小學
client 19130901 19160901 B初中
client 19160901 19190901 C高中
client 19190901 19230901 D大學
client 19230901 19601231 E公司
client 19601231 29991231 H退休在家

上面的每一條記錄都是不算末尾的,比如到19070901,client已經在A,而不是H了。所以除最后一條記錄因為狀態到目前都未改變的,其余的記錄實際上在結束日期那天,都不在是該條記錄結束日期那天的狀態。這種現象可以理解為算頭不算尾。

拉鏈表實現方式

1、定義兩個臨時表,一個為當日全量數據,另一個為需要新增或更新的數據;

CREATE VOLATILE TABLE VT_xxxx_NEW AS xxxx WITH NO DATA ON COMMIT PRESERVE ROWS;CREATE VOLATILE SET TABLE VT_xxxx_CHG,NO LOG AS xxxx WITH NO DATA ON COMMIT PRESERVE ROWS;

2、獲取當日全量數據

INSERT INTO VT_xxxx_NEW(xx) SELECT (xx,cur_date, max_date) FROM xxxx_sorce;

3、抽取新增或有變化的數據,從xxxx_NEW臨時表到xxxx_CHG臨時表;

INSERT INTO VT_xxxx_CHG(xx)SELECT xx FROM VT_xxxx_NEWWHERE (xx) NOT IN (select xx from xxxx_HIS where end_date='max_date');

4、更新歷史表的失效記錄的end_date為max值

UPDATE A1 FROM xxxx_HIS A1, VT_xxxx_CHG A2SET End_Date='current_date'WHERE A1.xx=A2.xx AND A1.End_Date='max_date';

5、將新增或者有變化的數據插入目標表

INSERT INTO xxxx_HIS SELECT * FROM VT_xxxx_CHG;

以商品數據為例

存在商品表 t_product,表結構如下:

列名 類型 說明
goods_id varchar(50) 商品編號
goods_status varchar(50) 商品狀態(待審核、待售、在售、已刪除)
createtime varchar(50) 商品創建日期
modifytime varchar(50) 商品修改日期

2019年12月20日的數據如下所示:

goods_id goods_status createtime modifytime
001 待審核 2019-12-20 2019-12-20
002 待售 2019-12-20 2019-12-20
003 在售 2019-12-20 2019-12-20
004 已刪除 2019-12-20 2019-12-20

商品的狀態,會隨著時間推移而變化,我們需要將商品的所有變化的歷史信息都保存下來。

方案一: 快照每一天的數據到數倉

該方案為:每一天都保存一份全量,將所有數據同步到數倉中,很多記錄都是重復保存,沒有任何變化。

12月20日(4條數據)
goods_id goods_status createtime modifytime
001 待審核 2019-12-18 2019-12-20
002 待售 2019-12-19 2019-12-20
003 在售 2019-12-20 2019-12-20
004 已刪除 2019-12-15 2019-12-20
12月21日(10條數據)
goods_id goods_status createtime modifytime
以下為12月20日快照數據
001 待審核 2019-12-18 2019-12-20
002 待售 2019-12-19 2019-12-20
003 在售 2019-12-20 2019-12-20
004 已刪除 2019-12-15 2019-12-20
以下為12月21日快照數據
001 待售(從待審核到待售) 2019-12-18 2019-12-21
002 待售 2019-12-19 2019-12-20
003 在售 2019-12-20 2019-12-20
004 已刪除 2019-12-15 2019-12-20
005(新商品) 待審核 2019-12-21 2019-12-21
006(新商品) 待審核 2019-12-21 2019-12-21
12月22日(18條數據)
goods_id goods_status createtime modifytime
以下為12月20日快照數據
001 待審核 2019-12-18 2019-12-20
002 待售 2019-12-19 2019-12-20
003 在售 2019-12-20 2019-12-20
004 已刪除 2019-12-15 2019-12-20
以下為12月21日快照數據
001 待售(從待審核到待售) 2019-12-18 2019-12-21
002 待售 2019-12-19 2019-12-20
003 在售 2019-12-20 2019-12-20
004 已刪除 2019-12-15 2019-12-20
005 待審核 2019-12-21 2019-12-21
006 待審核 2019-12-21 2019-12-21
以下為12月22日快照數據
001 待售 2019-12-18 2019-12-21
002 待售 2019-12-19 2019-12-20
003 已刪除(從在售到已刪除) 2019-12-20 2019-12-22
004 待審核 2019-12-21 2019-12-21
005 待審核 2019-12-21 2019-12-21
006 已刪除(從待審核到已刪除) 2019-12-21 2019-12-22
007 待審核 2019-12-22 2019-12-22
008 待審核 2019-12-22 2019-12-22
mysql數倉代碼實現

MySQL初始化

在MySQL中 lalian 庫和商品表用于到原始數據層

-- 創建數據庫create database if not exists lalian;-- 創建商品表create table if not exists `lalian`.`t_product`( 	goods_id varchar(50), -- 商品編號     goods_status varchar(50), -- 商品狀態     createtime varchar(50), -- 商品創建時間     modifytime varchar(50) -- 商品修改時間);

在MySQL中創建ods和dw層來模擬數倉

-- ods創建商品表create table if not exists `lalian`.`ods_t_product`( 	goods_id varchar(50), -- 商品編號 	goods_status varchar(50), -- 商品狀態 	createtime varchar(50), -- 商品創建時間 	modifytime varchar(50), -- 商品修改時間 	cdat varchar(10)   -- 模擬hive分區)default character set = 'utf8';-- dw創建商品表create table if not exists `lalian`.`dw_t_product`( 	goods_id varchar(50), -- 商品編號 	goods_status varchar(50), -- 商品狀態  	createtime varchar(50), -- 商品創建時間  	modifytime varchar(50), -- 商品修改時間  	cdat varchar(10)  -- 模擬hive分區)default character set = 'utf8';

增量導入12月20號數據

原始數據導入12月20號數據(4條)

insert into `lalian`.`t_product`(goods_id, goods_status, createtime, modifytime) values('001', '待審核', '2019-12-18', '2019-12-20'),('002', '待售', '2019-12-19', '2019-12-20'),('003', '在售', '2019-12-20', '2019-12-20'),('004', '已刪除', '2019-12-15', '2019-12-20');

注意:由于這里使用的MySQL來模擬的數倉所以直接使用insert into的方式導入數據,在企業中可能會使用hive來做數倉使用 kettle 或者 sqoop 或 datax 等來同步數據。

# 從原始數據層導入到ods 層insert into lalian.ods_t_productselect *,'20191220' from lalian.t_product ;# 從ods同步到dw層insert into lalian.dw_t_productselect * from lalian.ods_t_product where cdat='20191220';

查看dw層的運行結果

select * from lalian.dw_t_product where cdat='20191220';
goods_id goods_status createtime modifytime cdat
1 待審核 2019/12/18 2019/12/20 20191220
2 待售 2019/12/19 2019/12/20 20191220
3 在售 2019/12/20 2019/12/20 20191220
4 已刪除 2019/12/15 2019/12/20 20191220

增量導入12月21數據

原始數據層導入12月21日數據(6條數據)

UPDATE `lalian`.`t_product` SET goods_status = '待售', modifytime = '2019-12-21' WHERE goods_id = '001'; INSERT INTO `lalian`.`t_product`(goods_id, goods_status, createtime, modifytime) VALUES ('005', '待審核', '2019-12-21', '2019-12-21'), ('006', '待審核', '2019-12-21', '2019-12-21');

將數據導入到ods層與dw層

# 從原始數據層導入到ods 層insert into lalian.ods_t_productselect *,'20191221' from lalian.t_product ;# 從ods同步到dw層insert into lalian.dw_t_productselect * from lalian.ods_t_product where cdat='20191221';

查看dw層的運行結果

select * from lalian.dw_t_product where cdat='20191221';
goods_id goods_status createtime modifytime cdat
1 待售 2019/12/18 2019/12/21 20191221
2 待售 2019/12/19 2019/12/20 20191221
3 在售 2019/12/20 2019/12/20 20191221
4 已刪除 2019/12/15 2019/12/20 20191221
5 待審核 2019/12/21 2019/12/21 20191221
6 待審核 2019/12/21 2019/12/21 20191221

增量導入12月22日數據

原始數據層導入12月22日數據(6條數據)

UPDATE `lalian`.`t_product` SET goods_status = '已刪除', modifytime = '2019-12-22' WHERE goods_id = '003';UPDATE `lalian`.`t_product` SET goods_status = '已刪除', modifytime = '2019-12-22' WHERE goods_id = '006';INSERT INTO `lalian`.`t_product`(goods_id, goods_status, createtime, modifytime) VALUES('007', '待審核', '2019-12-22', '2019-12-22'),('008', '待審核', '2019-12-22', '2019-12-22');

將數據導入到ods層與dw層

# 從原始數據層導入到ods 層 insert into lalian.ods_t_product select *,'20191222' from lalian.t_product ; # 從ods同步到dw層 insert into lalian.dw_t_productpeizhiwenjian select * from lalian.ods_t_product where cdat='20191222';

查看dw層的運行結果

select * from lalian.dw_t_product where cdat='20191222';
goods_id goods_status createtime modifytime cdat
1 待售 2019/12/18 2019/12/21 20191222
2 待售 2019/12/19 2019/12/20 20191222
3 已刪除 2019/12/20 2019/12/22 20191222
4 已刪除 2019/12/15 2019/12/20 20191222
5 待審核 2019/12/21 2019/12/21 20191222
6 已刪除 2019/12/21 2019/12/22 20191222
7 待審核 2019/12/22 2019/12/22 20191222
8 待審核 2019/12/22 2019/12/22 20191222

查看dw層的運行結果

select * from lalian.dw_t_product;
goods_id goods_status createtime modifytime cdat
1 待審核 2019/12/18 2019/12/20 20191220
2 待售 2019/12/19 2019/12/20 20191220
3 在售 2019/12/20 2019/12/20 20191220
4 已刪除 2019/12/15 2019/12/20 20191220
1 待售 2019/12/18 2019/12/21 20191221
2 待售 2019/12/19 2019/12/20 20191221
3 在售 2019/12/20 2019/12/20 20191221
4 已刪除 2019/12/15 2019/12/20 20191221
5 待審核 2019/12/21 2019/12/21 20191221
6 待審核 2019/12/21 2019/12/21 20191221
1 待售 2019/12/18 2019/12/21 20191222
2 待售 2019/12/19 2019/12/20 20191222
3 已刪除 2019/12/20 2019/12/22 20191222
4 已刪除 2019/12/15 2019/12/20 20191222
5 待審核 2019/12/21 2019/12/21 20191222
6 已刪除 2019/12/21 2019/12/22 20191222
7 待審核 2019/12/22 2019/12/22 20191222
8 待審核 2019/12/22 2019/12/22 20191222

從上述案例,可以看到:表每天保留一份全量,每次全量中會保存很多不變的信息,如果數據量很大的話,對存儲是極大的浪費,可以將表設計為拉鏈表,既能滿足反應數據的歷史狀態,又可以最大限度地節省存儲空間。

方案二: 使用拉鏈表保存歷史快照

拉鏈表不存儲冗余的數據,只有某行的數據發生變化,才需要保存下來,相比每次全量同步會節省存儲空間

能夠查詢到歷史快照

額外的增加了兩列(dw_start_date、dw_end_date),為數據行的生命周期。

12月20日商品拉鏈表的數據
goods_id goods_status createtime modifytime dw_start_date dw_end_date
001 待審核 2019-12-18 2019-12-20 2019-12-20 9999-12-31
002 待售 2019-12-19 2019-12-20 2019-12-20 9999-12-31
003 在售 2019-12-20 2019-12-20 2019-12-20 9999-12-31
004 已刪除 2019-12-15 2019-12-20 2019-12-20 9999-12-31

12月20日的數據是全新的數據導入到dw表

  • dw_start_date表示某一條數據的生命周期起始時間,即數據從該時間開始有效(即生效日期)
  • dw_end_date表示某一條數據的生命周期結束時間,即數據到這一天(不包含)(即失效日期)
  • dw_end_date為 9999-12-31,表示當前這條數據是最新的數據,數據到9999-12-31才過期
12月21日商品拉鏈表的數據
goods_id goods_status createtime modifytime dw_start_date dw_end_date
001 待審核 2019-12-18 2019-12-20 2019-12-20 2019-12-21
002 待售 2019-12-19 2019-12-20 2019-12-20 9999-12-31
003 在售 2019-12-20 2019-12-20 2019-12-20 9999-12-31
004 已刪除 2019-12-15 2019-12-20 2019-12-20 9999-12-31
001(變) 待售 2019-12-18 2019-12-21 2019-12-21 9999-12-31
005(新) 待審核 2019-12-21 2019-12-21 2019-12-21 9999-12-31

拉鏈表中沒有存儲冗余的數據,即只要數據沒有變化,無需同步

  • 001編號的商品數據的狀態發生了變化(從待審核 → 待售),需要將原有的dw_end_date從9999-12-31變為2019-12-21,表示待審核狀態,在2019/12/20(包含) – 2019/12/21(不包含)有效;
  • 001編號新的狀態重新保存了一條記錄,dw_start_date為2019/12/21,dw_end_date為9999/12/31
  • 新數據005、006、dw_start_date為2019/12/21,dw_end_date為9999/12/31。
12月22日商品拉鏈表的數據
goods_id goods_status createtime modifytime dw_start_date dw_end_date
001 待審核 2019-12-18 2019-12-20 2019-12-20 2019-12-21
002 待售 2019-12-19 2019-12-20 2019-12-20 9999-12-31
003 在售 2019-12-20 2019-12-20 2019-12-20 2019-12-22
004 已刪除 2019-12-15 2019-12-20 2019-12-20 9999-12-31
001 待售 2019-12-18 2019-12-21 2019-12-21 9999-12-31
005 待審核 2019-12-21 2019-12-21 2019-12-21 9999-12-31
006 待審核 2019-12-21 2019-12-21 2019-12-21 9999-12-31
003(變) 已刪除 2019-12-20 2019-12-22 2019-12-22 9999-12-31
007(新) 待審核 2019-12-22 2019-12-22 2019-12-22 9999-12-31
008(新) 待審核 2019-12-22 2019-12-22 2019-12-22 9999-12-31

拉鏈表中沒有存儲冗余的數據,即只要數據沒有變化,無需同步

  • 003編號的商品數據的狀態發生了變化(從在售→已刪除),需要將原有的 dw_end_date從9999-12-31變為2019-12-22,表示在售狀態,在2019/12/20(包含) – 2019/12/22(不包含) 有效
  • 003編號新的狀態重新保存了一條記錄,dw_start_date為2019-12-22,dw_end_date為9999-12-31
  • 新數據007、008、dw_start_date為2019-12-22,dw_end_date為9999-12-31
MySQL數倉拉鏈表快照實現

操作流程:

  1. 在原有dw層表上,添加額外的兩列
  2. 只同步當天修改的數據到ods層
  3. 拉鏈表算法實現
  4. 拉鏈表的數據為:當天最新的數據 UNION ALL 歷史數據

代碼實現

在MySQL中lalian庫和商品表用于到原始數據層

-- 創建數據庫create database if not exists lalian;-- 創建商品表create table if not exists `lalian`.`t_product2`( 	goods_id varchar(50), -- 商品編號 	goods_status varchar(50), -- 商品狀態     createtime varchar(50), -- 商品創建時間     modifytime varchar(50) -- 商品修改時間)default character set = 'utf8';

在MySQL中創建ods和dw層 模擬數倉

-- ods創建商品表create table if not exists `lalian`.`ods_t_product2`( 	goods_id varchar(50), -- 商品編號 	goods_status varchar(50), -- 商品狀態 	createtime varchar(50), -- 商品創建時間 	modifytime varchar(50), -- 商品修改時間 	cdat varchar(10)   -- 模擬hive分區)default character set = 'utf8';-- dw創建商品表create table if not exists `lalian`.`dw_t_product2`( 	goods_id varchar(50), -- 商品編號 	goods_status varchar(50), -- 商品狀態 	createtime varchar(50), -- 商品創建時間 	modifytime varchar(50), -- 商品修改時間 	dw_start_date varchar(12), -- 生效日期 	dw_end_date varchar(12), -- 失效時間 	cdat varchar(10)  -- 模擬hive分區)default character set = 'utf8';

全量導入2019年12月20日數據

原始數據層導入12月20日數據(4條數據)

insert into `lalian`.`t_product_2`(goods_id, goods_status, createtime, modifytime) values('001', '待審核', '2019-12-18', '2019-12-20'),('002', '待售', '2019-12-19', '2019-12-20'),('003', '在售', '2019-12-20', '2019-12-20'),('004', '已刪除', '2019-12-15', '2019-12-20');

將數據導入到數倉中的ods層

insert into lalian.ods_t_product2select *,'20191220' from lalian.t_product2 where modifytime >='2019-12-20';

將數據從ods層導入到dw層

insert into lalian.dw_t_product2select goods_id, goods_status, createtime, modifytime, modifytime,'9999-12-31', cdat from lalian.ods_t_product2 where cdat='20191220';

增量導入2019年12月21日數據

原始數據層導入12月21日數據(6條數據)

UPDATE `lalian`.`t_product2` SET goods_status = '待售', modifytime = '2019-12-21' WHERE goods_id = '001';INSERT INTO `lalian`.`t_product2`(goods_id, goods_status, createtime, modifytime) VALUES('005', '待審核', '2019-12-21', '2019-12-21'),('006', '待審核', '2019-12-21', '2019-12-21');

原始數據層同步到ods層

insert into lalian.ods_t_product2select *,'20191221' from lalian.t_product2 where modifytime >='2019-12-21';

編寫ods層到dw層重新計算 dw_end_date

select t1.goods_id, t1.goods_status, t1.createtime, t1.modifytime,        t1.dw_start_date,        case when (t2.goods_id is not null and t1.dw_end_date>'2019-12-21') then '2019-12-21'else t1.dw_end_date end as dw_end_date ,        t1.cdatfrom lalian.dw_t_product2 t1left join (select * from lalian.ods_t_product2 where cdat='20191221')t2 on t1.goods_id=t2.goods_idunionselect goods_id, goods_status, createtime, modifytime, modifytime,'9999-12-31', cdat from lalian.ods_t_product2 where cdat='20191221';

執行結果如下:

goods_id goods_status createtime modifytime dw_start_date dw_end_date cdat
1 待審核 2019-12-18 2019-12-20 2019-12-20 2019-12-21 20191220
2 待售 2019-12-19 2019-12-20 2019-12-20 9999-12-31 20191220
3 在售 2019-12-20 2019-12-20 2019-12-20 9999-12-31 20191220
4 已刪除 2019-12-15 2019-12-20 2019-12-20 9999-12-31 20191220
1 待售 2019-12-18 2019-12-21 2019-12-21 9999-12-31 20191221
5 待審核 2019-12-21 2019-12-21 2019-12-21 9999-12-31 20191221
6 待審核 2019-12-21 2019-12-21 2019-12-21 9999-12-31 20191221

拉鏈歷史表,既能滿足反應數據的歷史狀態,又可以最大程度的節省存儲。我們做拉鏈表的時候要確定拉鏈表的粒度,比如說拉鏈表每天只取一個狀態,也就是說如果一天有3個狀態變更,我們只取最后一個狀態,這種天粒度的表其實已經能解決大部分的問題了。

推薦學習:mysql

? 版權聲明
THE END
喜歡就支持一下吧
點贊6 分享