數據倉庫-拉鏈表, 流水表, 全量表, 增量表, 切片表
1 增量表
1.1 概念

增量表:新增數據,增量數據是上次導出之后的新數據。比如說,從24號到25號新增了那些數據,改變了哪些數據,這些都會存儲在增量表的25號分區里面。
記錄每次增加的量,而不是總量;
增量表,只報變化量,無變化不用報
每天一個分區
1.2 例子


注:因為數倉都是T+1的,所以7號的數據是8號加工出來的
加工邏輯:
1.根據修改時間,把修改時間等於昨天(即7號)的數據抽取到ods層wedw_ods.test_user_info_20200407中
2.找出20200406未修改的數據放入20200407分區中
和數倉表wedw_dwd.test_user_info_di 分區date_id = ‘2020-04-06’通過主鍵用戶id進行關聯,先把wedw_dwd.test_user_info_di中存在且wedw_ods.test_user_info_20200407中不存在的數據插入到wedw_dwd.test_user_info_di分區date_id=2020-04-07中
3.最后把wedw_ods.test_user_info_20200407表的所有數據插入到wedw_dwd.test_user_info_di分區date_id=2020-04-07
insert overwrite table wedw_dwd.test_user_info_di PARTITION(date_id='2020-04-07')
select
a.user_id
,a.user_name
,a.user_age
,a.user_cellphone
,a.create_time
,a.update_time
from wedw_dwd.test_user_info_di a
left join wedw_ods.test_user_info_20200407 b
on b.user_id=a.user_id
where a.date_id = '2020-04-06'
and b.user_id is null;
insert into table wedw_dwd.test_user_info_di PARTITION(date_id='2020-04-07')
select
coalesce(user_id'-99') as user_id
,coalesce(user_name,'-99') as user_name
,coalesce(user_age,0) as user_age
,coalesce(user_cellphone,'-99') as user_cellphone
,coalesce(create_time,cast('1700-01-01 00:00:00' as timestamp )) as create_time
,coalesce(update_time,cast('1700-01-01 00:00:00' as timestamp )) as update_time
from wedw_ods.test_user_info_20200407 b ;
--僅保留近7天的分區
alter table wedw_dwd.test_user_info_di drop if EXISTS partition(date_id='2020-03-31');
特殊增量表:da表,每天的分區就是當天的數據,其數據特點就是數據產生后就不會發生變化,如日志表
2 全量表
2.1 概念

每天計算所有的數據,並覆蓋寫入全量表。
全量表,有無變化,都要報
每次上報的數據都是所有的數據(變化的 + 沒有變化的)
只有一個分區(或者說沒有分區)
每次往全量表里面寫數據都會覆蓋之前的數據,所以全量表不能記錄數據歷史變化,只有截止到當前最新的、全量的數據。
2.2 小結
缺點:
無法反映數據歷史變化,只有截止到當天(t+1)最新的、全量的數據。
2.3 例子
3 快照表

既然全量表無法反映歷史,那么要能查到歷史數據情況又該怎么辦呢?這個時候快照表就派上用途了
按日分區,記錄截止數據日期的全量數據(每個分區里面的數據都是分區時間對應的前一天的所有全量數據,t+1)
快照表,有無變化,都要報
每次上報的數據都是所有的數據(變化的 + 沒有變化的)
每個分區里面的數據都是分區時間對應的前一天的所有全量數據,比如說當前數據表有3個分區,24號,25號,26號。其中,24號分區里面的數據就是從歷史到23號的所有數據,25號分區里面的數據就是從歷史到24號的所有數據,以此類推。
一天一個分區
快照表的25號分區和24號分區(都是t+1,實際時間分別對應26號和25號)的數據相減就是實際時間25號到26號有變化的、增加的數據,也就相當於增量表里面25號分區的數據。
缺點:
數據量大的時候,其實每個分區都存儲了許多重復的數據,非常的浪費存儲空間。
4 拉鏈表
4.1 概念
拉鏈表目的是解決快照表數據冗余問題,還能維護數據歷史狀態和最新狀態。拉鏈表根據拉鏈粒度的不同,實際上相當於快照,只不過做了優化,去除了一部分不變的記錄而已,通過拉鏈表可以很方便的還原出拉鏈時點的客戶記錄。
拉鏈表記錄截止數據日期的全量數據
記錄一個事物從開始,一直到當前狀態的所有變化的信息;
拉鏈表每次上報的都是歷史記錄的最終狀態,是記錄在當前時刻的歷史總量;
當前記錄存的是當前時間之前的所有歷史記錄的最后變化量(總量);
一般只有一個分區
也可以有分區表,有些不變的數據或者是已經達到狀態終點的數據就會放在分區里面,分區字段一般為開始時間:start_date和結束時間:end_date。一般在該天有效的數據,它的end_date是大於等於該天的日期的。
獲取某一天全量的數據,可以通過表中的start_date和end_date來做篩選,選出固定某一天的數據。例如我想取截止到20190813的全量數據,其where過濾條件就是where start_date<=‘20190813’ and end_date>=20190813。
4.2 小結
適用情況:
數據量比較大
表中的部分字段會被更新
需要查看某一個時間點或者時間段的歷史快照信息
查看某一個訂單在歷史某一個時間點的狀態
某一個用戶在過去某一段時間,下單次數
更新的比例和頻率不是很大
如果表中信息變化不是很大,每天都保留一份全量,那么每次全量中會保存很多不變的信息,對存儲是極大的浪費。此時可以用拉鏈表。
優點
滿足反應數據的歷史狀態
最大程度節省存儲
4.3 例子

增加兩個字段:
start_time
表示該條記錄的生命周期開始時間——周期快照時的狀態
end_time
該條記錄的生命周期結束時間
end_time= ‘9999-12-31’ 表示該條記錄目前處於有效狀態
查詢4月8日的所有有效的記錄:
select * from wedw_dwd.test_user_info_dz where date_id = ‘2020-04-08’ and end_time = ‘9999-12-31’;
結果如下

查詢2020-04-07的歷史快照:
select * from wedw_dwd.test_user_info_dz where date_id = ‘2020-04-08’ and start_time <= ‘2020-04-07’ and end_time >= ‘2020-04-07’;
結果如下:

加工邏輯:
注:第一次加工的時候需要初始化所有數據,start_time設置為數據日期2020-04-06 ,end_time設置為9999-12-31
--分桶
set hive.enforce.bucketing=FALSE;
--分區
set hive.exec.dynamic.partition=FALSE;
set hive.exec.dynamic.partition.mode=nostrick;
set hive.exec.compress.output=true;
set mapred.output.compress=true;
set mapred.output.compression.type=BLOCK;
set mapred.output.compression.codec=org.apache.hadoop.io.compress.SnappyCodec;
alter table wedw_dwd.test_user_info_dz drop if EXISTS PARTITION(date_id='${HIVE_DATA_DATE}');
-- wedw_dwd.test_user_info_dz 存在, wedw_ods.test_user_info_${DATA_DATE} 不存在的
--或者都存在的閉鏈的 插入到 wedw_dwd.test_user_info_dz 下一個分區
insert overwrite table wedw_dwd.test_user_info_dz PARTITION(date_id='${HIVE_DATA_DATE}')
select
a.user_id
,a.user_name
,a.user_age
,a.user_cellphone
,a.create_time
,a.update_time
,a.start_time
,a.end_time
from wedw_dwd.test_user_info_dz a
left join wedw_ods.test_user_info_${DATA_DATE} b on b.user_id=a.user_id and b.create_time < '${HIVE_DATA_DATE+1}'
where a.date_id = '${HIVE_DATA_DATE-1}'
and (b.user_id is null
or (b.user_id is not null and a.end_time <='${HIVE_DATA_DATE-1}')
)
;
-- 把wedw_dwd.test_user_info_dz, wedw_ods.test_user_info_${DATA_DATE} 都存在的開鏈的 全部閉鏈 插入到 wedw_dwd.test_user_info_dz 下一個分區
insert into table wedw_dwd.test_user_info_dz PARTITION(date_id='${HIVE_DATA_DATE}')
select
a.user_id
,a.user_name
,a.user_age
,a.user_cellphone
,a.create_time
,a.update_time
,a.start_time
,'${HIVE_DATA_DATE-1}' end_time
from wedw_dwd.test_user_info_dz a
inner join wedw_ods.test_user_info_${DATA_DATE} b on b.user_id=a.user_id and b.create_time < '${HIVE_DATA_DATE+1}'
where a.date_id = '${HIVE_DATA_DATE-1}'
and a.end_time >'${HIVE_DATA_DATE-1}'
;
-- 把wedw_ods.test_user_info_${DATA_DATE}, 插入到 wedw_dwd.test_user_info_dz 下一個分區
insert into table wedw_dwd.test_user_info_dz PARTITION(date_id='${HIVE_DATA_DATE}')
select
a.user_id
,a.user_name
,a.user_age
,a.user_cellphone
,a.create_time
,a.update_time
,'${HIVE_DATA_DATE}' start_time,
,'9999-12-31' end_time
from wedw_ods.test_user_info_${DATA_DATE} b
where b.create_time < '${HIVE_DATA_DATE+1}';
--僅保留近7天的數據
alter table wedw_dwd.test_user_info_dz drop if EXISTS partition(date_id='${HIVE_DATA_DATE-7}');
5 流水表
5.1 概念
對於表的每一個修改都會記錄,可以用於反映實際記錄的變更。
5.2 流水表與拉鏈表區別
拉鏈表通常是對賬戶信息的歷史變動進行處理保留的結果,流水表是每天的交易形成的歷史;
流水表用於統計業務相關情況,拉鏈表用於統計賬戶及客戶的情況
6 切片表
切片表根據基礎表,往往只反映某一個維度的相應數據。其表結構與基礎表結構相同,但數據往往只有某一維度,或者某一個事實條件的數據
轉自https://blog.csdn.net/xingdianp/article/details/110307783
