1.定義
拉鏈表是一種數據庫設計模,用於儲存歷史數據和分析時間維度的數據。
所謂拉鏈,就是記錄歷史。記錄一個事物從開始,一直到當前狀態的所有變化的信息。
關鍵點:
- 儲存開始時間和結束時間。
- 開始時間和結束時間首尾相接,形成鏈式結構。
拉鏈表一般用於解決歷史版本查詢的問題,也可用於解決數值區間問題,查詢效率高,占用空間小。
如圖是用戶手機號拉鏈表:
開鏈就是第一次插入數據,這條數據沒有之前的記錄與之對應,只需要設定START_DATE並將END_DATE置為很久以后(比如9999年12月31日)的日期即可。
關鏈就是設置整條鏈的結尾,將END_DATE置為一個有業務意義的日期(比如三天前或一個月后都可以)即可。
2.原因
為什么要設計拉鏈表?
因為要追蹤數據 全量快照表空間占用大,增量表雖然小,但是無法直接在一個分區內直接看到所有的軌跡數據,同時前兩者無法直接查看變化時間。
用拉鏈表可以做到記錄變化時間也做的到一條語句直接查詢,最近的軌跡,還避免全分區掃描。
SELECT * FROM LINK_TABLE WHERE USER = 1 AND ? >= START_DATE AND ? < END_DATE
3.使用場景案例
在數據倉庫的數據模型設計過程中,經常會遇到下面這種表的設計:
- 有一些表的數據量很大,比如一張用戶表,大約10億條記錄,50個字段,這種表,即使使用ORC壓縮,單張表的存儲也會超過100G,在HDFS使用雙備份或者三備份的話就更大一些。
- 表中的部分字段會被update更新操作,如用戶聯系方式,產品的描述信息,訂單的狀態等等。
- 需要查看某一個時間點或者時間段的歷史快照信息,比如,查看某一個訂單在歷史某一個時間點的狀態。
- 表中的記錄變化的比例和頻率不是很大,比如,總共有10億的用戶,每天新增和發生變化的有200萬左右,變化的比例占的很小。
4.拉鏈表的合並與拆分
由於某些特殊的業務需要,或為了方便查詢,或因為歷史遺留數據,常常造成拉鏈表的數據太單一或拉鏈表的數據太多,這時可能會需要對拉鏈表進行合並或拆分。
1. 合並
現在有兩張表:LINK_TABLE(數據為大寫字母),LINK_DEMO(數據為小寫字母),現在要查ID為1數據為X和y的START_DATE和END_DATE。
我要查出所有ID的所有屬性組合的起止時間。
那么經過對表格的觀察,我們可以畫出如下的一個數軸。
最終結果應該是:
代碼如下:
SELECT A.ID, A.DATA, B.DATA, CASE WHEN A.START_DATE<B.START_DATE THEN B.START_DATE ELSE A.START_DATE END, CASE WHEN A.END_DATE>B.END_DATE THEN B.END_DATE ELSE A.END_DATE END FROM LINK_DEMO A JOIN LINK_TABLE B ON A.ID=B.ID AND (A.START_DATE < B.END_DATE OR B.START_DATE < A.END_DATE);
2.拆分
拆分是合並的逆操作,就是將一個存了多個屬性的拉鏈表拆成多個含有少量屬性的拉鏈表。比如我們現在已經有這張LINK_COMBINE表了,我們想將它拆成LINK_DEMO和LINK_TABLE。