在有些情況下,為了保持歷史的一些狀態(tài)谴轮,需要用拉鏈表來做,這樣做目的在可以保留所有狀態(tài)的情況下可以節(jié)省空間吹埠。
拉鏈表適用于以下幾種情況吧
數(shù)據(jù)量有點大第步,表中某些字段有變化,但是呢變化的頻率也不是很高缘琅,業(yè)務(wù)需求呢又需要統(tǒng)計這種變化狀態(tài)粘都,每天全量一份呢,有點不太現(xiàn)實刷袍,
不僅浪費(fèi)了存儲空間翩隧,有時可能業(yè)務(wù)統(tǒng)計也有點麻煩,這時呻纹,拉鏈表的作用就提現(xiàn)出來了堆生,既節(jié)省空間,又滿足了需求雷酪。
一般在數(shù)倉中通過增加begin_date,en_date來表示淑仆,如下例,后兩列是start_date和end_date.
1 2016-08-20 2016-08-20 創(chuàng)建 2016-08-20 2016-08-20
1 2016-08-20 2016-08-21 支付 2016-08-21 2016-08-21
1 2016-08-20 2016-08-22 完成 2016-08-22 9999-12-31
2 2016-08-20 2016-08-20 創(chuàng)建 2016-08-20 2016-08-20
2 2016-08-20 2016-08-21 完成 2016-08-21 9999-12-31
3 2016-08-20 2016-08-20 創(chuàng)建 2016-08-20 2016-08-21
3 2016-08-20 2016-08-22 支付 2016-08-22 9999-12-31
4 2016-08-21 2016-08-21 創(chuàng)建 2016-08-21 2016-08-21
4 2016-08-21 2016-08-22 支付 2016-08-22 9999-12-31
5 2016-08-22 2016-08-22 創(chuàng)建 2016-08-22 9999-12-31
begin_date表示該條記錄的生命周期開始時間哥力,end_date表示該條記錄的生命周期結(jié)束時間蔗怠;
end_date = ‘9999-12-31’表示該條記錄目前處于有效狀態(tài)墩弯;
如果查詢當(dāng)前所有有效的記錄,則select * from order_his where dw_end_date = ‘9999-12-31′
如果查詢2016-08-21的歷史快照寞射,則select * from order_his where begin_date <= ‘2016-08-21′ and end_date >= ‘2016-08-21’
再簡單介紹一下拉鏈表的更新:
假設(shè)以天為維度渔工,以每天的最后一個狀態(tài)為當(dāng)天的最終狀態(tài)。
以一張訂單表為例桥温,如下是原始數(shù)據(jù)引矩,每天的訂單狀態(tài)明細(xì)
1 2016-08-20 2016-08-20 創(chuàng)建
2 2016-08-20 2016-08-20 創(chuàng)建
3 2016-08-20 2016-08-20 創(chuàng)建
1 2016-08-20 2016-08-21 支付
2 2016-08-20 2016-08-21 完成
4 2016-08-21 2016-08-21 創(chuàng)建
1 2016-08-20 2016-08-22 完成
3 2016-08-20 2016-08-22 支付
4 2016-08-21 2016-08-22 支付
5 2016-08-22 2016-08-22 創(chuàng)建
根據(jù)拉鏈表我們希望得到的是
1 2016-08-20 2016-08-20 創(chuàng)建 2016-08-20 2016-08-20
1 2016-08-20 2016-08-21 支付 2016-08-21 2016-08-21
1 2016-08-20 2016-08-22 完成 2016-08-22 9999-12-31
2 2016-08-20 2016-08-20 創(chuàng)建 2016-08-20 2016-08-20
2 2016-08-20 2016-08-21 完成 2016-08-21 9999-12-31
3 2016-08-20 2016-08-20 創(chuàng)建 2016-08-20 2016-08-21
3 2016-08-20 2016-08-22 支付 2016-08-22 9999-12-31
4 2016-08-21 2016-08-21 創(chuàng)建 2016-08-21 2016-08-21
4 2016-08-21 2016-08-22 支付 2016-08-22 9999-12-31
5 2016-08-22 2016-08-22 創(chuàng)建 2016-08-22 9999-12-31
可以看出 1,2策治,3脓魏,4每個訂單的狀態(tài)都有,并且也能統(tǒng)計到當(dāng)前的有效狀態(tài)通惫。
本例以hive為例,只考慮到實現(xiàn)混蔼,與性能無關(guān)
首先創(chuàng)建表
CREATE
TABLE
orders (
orderid ``INT``,
createtime STRING,
modifiedtime STRING,
status STRING
) row format delimited fields terminated ``by
'\t'
CREATE
TABLE
ods_orders_inc (
orderid ``INT``,
createtime STRING,
modifiedtime STRING,
status STRING
) PARTITIONED ``BY
(``day
STRING)
row format delimited fields terminated ``by
'\t'
CREATE
TABLE
dw_orders_his (
orderid ``INT``,
createtime STRING,
modifiedtime STRING,
status STRING,
dw_start_date STRING,
dw_end_date STRING
) row format delimited fields terminated ``by
'\t'
;
首先全量更新履腋,我們先到2016-08-20為止的數(shù)據(jù)。
初始化惭嚣,先把2016-08-20的數(shù)據(jù)初始化進(jìn)去
INSERT
overwrite ``TABLE
ods_orders_inc PARTITION (``day
= ``'2016-08-20'``)
SELECT
orderid,createtime,modifiedtime,status
FROM
orders
WHERE
createtime < ``'2016-08-21'
and
modifiedtime <``'2016-08-21'``;
刷到dw中
INSERT
overwrite ``TABLE
dw_orders_his
SELECT
orderid,createtime,modifiedtime,status,
createtime ``AS
dw_start_date,
'9999-12-31'
AS
dw_end_date
FROM
ods_orders_inc
WHERE
day
= ``'2016-08-20'``;
如下結(jié)果
select
* ``from
dw_orders_his;
OK
1 2016-08-20 2016-08-20 創(chuàng)建 2016-08-20 9999-12-31
2 2016-08-20 2016-08-20 創(chuàng)建 2016-08-20 9999-12-31
3 2016-08-20 2016-08-20 創(chuàng)建 2016-08-20 9999-12-31
剩余需要進(jìn)行增量更新
INSERT
overwrite ``TABLE
ods_orders_inc PARTITION (``day
= ``'2016-08-21'``)
SELECT
orderid,createtime,modifiedtime,status
FROM
orders
WHERE
(createtime = ``'2016-08-21'
and
modifiedtime = ``'2016-08-21'``) ``OR
modifiedtime = ``'2016-08-21'``;
select
* ``from
ods_orders_inc ``where
day``=``'2016-08-21'``;
OK
1 2016-08-20 2016-08-21 支付 2016-08-21
2 2016-08-20 2016-08-21 完成 2016-08-21
4 2016-08-21 2016-08-21 創(chuàng)建 2016-08-21
先放到增量表中遵湖,然后進(jìn)行關(guān)聯(lián)到一張臨時表中,在插入到新表中
DROP
TABLE
IF EXISTS dw_orders_his_tmp;
CREATE
TABLE
dw_orders_his_tmp ``AS
SELECT
orderid,
createtime,
modifiedtime,
status,
dw_start_date,
dw_end_date
FROM
(
SELECT
a.orderid,
a.createtime,
a.modifiedtime,
a.status,
a.dw_start_date,
CASE
WHEN
b.orderid ``IS
NOT
NULL
AND
a.dw_end_date > ``'2016-08-21'
THEN
'2016-08-21'
ELSE
a.dw_end_date ``END
AS
dw_end_date
FROM
dw_orders_his a
left
outer
join
(``SELECT
* ``FROM
ods_orders_inc ``WHERE
day
= ``'2016-08-21'``) b
ON
(a.orderid = b.orderid)
UNION
ALL
SELECT
orderid,
createtime,
modifiedtime,
status,
modifiedtime ``AS
dw_start_date,
'9999-12-31'
AS
dw_end_date
FROM
ods_orders_inc
WHERE
day
= ``'2016-08-21'
) x
ORDER
BY
orderid,dw_start_date;
INSERT
overwrite ``TABLE
dw_orders_his
SELECT
* ``FROM
dw_orders_his_tmp;
在根據(jù)上面步驟把2016-08-22號的數(shù)據(jù)更新進(jìn)去晚吞,最后結(jié)果如下
select
* ``from
dw_orders_his;
OK
1 2016-08-20 2016-08-20 創(chuàng)建 2016-08-20 2016-08-20
1 2016-08-20 2016-08-21 支付 2016-08-21 2016-08-21
1 2016-08-20 2016-08-22 完成 2016-08-22 9999-12-31
2 2016-08-20 2016-08-20 創(chuàng)建 2016-08-20 2016-08-20
2 2016-08-20 2016-08-21 完成 2016-08-21 9999-12-31
3 2016-08-20 2016-08-20 創(chuàng)建 2016-08-20 2016-08-21
3 2016-08-20 2016-08-22 支付 2016-08-22 9999-12-31
4 2016-08-21 2016-08-21 創(chuàng)建 2016-08-21 2016-08-21
4 2016-08-21 2016-08-22 支付 2016-08-22 9999-12-31
5 2016-08-22 2016-08-22 創(chuàng)建 2016-08-22 9999-12-31
至此延旧,就得到了我們想要的數(shù)據(jù)。