一文搞定数据仓库之拉链表,流水表,全量表,增量表

1. 全量表:天天的全部的最新状态的数据,
2. 增量表:天天的新增数据,增量数据是上次导出以后的新数据。
3. 拉链表:维护历史状态,以及最新状态数据的一种表,拉链表根据拉链粒度的不一样,实际上至关于快照,只不过作了优化,去除了一部分不变的记录而已,经过拉链表能够很方便的还原出拉链时点的客户记录。
4. 流水表: 对于表的每个修改都会记录,能够用于反映实际记录的变动。 

拉链表一般是对帐户信息的历史变更进行处理保留的结果,流水表是天天的交易造成的历史;
流水表用于统计业务相关状况,拉链表用于统计帐户及客户的状况
数据仓库之拉链表(原理、设计以及在Hive中的实现)


在有些状况下,为了保持历史的一些状态,须要用拉链表来作,这样作目的在能够保留全部状态的状况下能够节省空间。

拉链表适用于如下几种状况吧

数据量有点大,表中某些字段有变化,可是呢变化的频率也不是很高,业务需求呢又须要统计这种变化状态,天天全量一份呢,有点不太现实,

不只浪费了存储空间,有时可能业务统计也有点麻烦,这时,拉链表的做用就提现出来了,既节省空间,又知足了需求。

通常在数仓中经过增长begin_date,en_date来表示,以下例,后两列是start_date和end_date.
 
1  2016-08-20  2016-08-20  建立 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  建立 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  建立 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  建立 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  建立 2016-08-22  9999-12-31
begin_date表示该条记录的生命周期开始时间,end_date表示该条记录的生命周期结束时间;

end_date = ‘9999-12-31’表示该条记录目前处于有效状态;

若是查询当前全部有效的记录,则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’

再简单介绍一下拉链表的更新:

假设以天为维度,以天天的最后一个状态为当天的最终状态。

以一张订单表为例,以下是原始数据,天天的订单状态明细

1   2016-08-20  2016-08-20  建立
2   2016-08-20  2016-08-20  建立
3   2016-08-20  2016-08-20  建立
1   2016-08-20  2016-08-21  支付
2   2016-08-20  2016-08-21  完成
4   2016-08-21  2016-08-21  建立
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  建立
根据拉链表咱们但愿获得的是

 
1  2016-08-20  2016-08-20  建立 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  建立 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  建立 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  建立 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  建立 2016-08-22  9999-12-31
能够看出 1,2,3,4每一个订单的状态都有,而且也能统计到当前的有效状态。

本例以hive为例,只考虑到实现,与性能无关

首先建立表
 
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为止的数据。

初始化,先把2016-08-20的数据初始化进去
 
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';

以下结果
 
select * from dw_orders_his;
OK
1  2016-08-20  2016-08-20  建立 2016-08-20  9999-12-31
2  2016-08-20  2016-08-20  建立 2016-08-20  9999-12-31
3  2016-08-20  2016-08-20  建立 2016-08-20  9999-12-31
剩余须要进行增量更新

 
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  建立 2016-08-21
先放到增量表中,而后进行关联到一张临时表中,在插入到新表中

 
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;
在根据上面步骤把2016-08-22号的数据更新进去,最后结果以下

 
select * from dw_orders_his;
OK
1  2016-08-20  2016-08-20  建立 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  建立 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  建立 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  建立 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  建立 2016-08-22  9999-12-31
至此,就获得了咱们想要的数据。


值得注意的是,订单表中数据同一天有屡次状态更新,应以天天的最后一个状态为当天的最终状态。好比一天以内订单状态建立,支付,完成都有,应拉取最终的状态进行拉练表更新,不然后面的数据可能就会出现异常,好比html

6  2016-08-22  2016-08-22  建立 2016-08-22  9999-12-31
6  2016-08-22  2016-08-22  支付 2016-08-22  9999-12-31
6  2016-08-22  2016-08-22  完成 2016-08-22  9999-12-31


http://www.cnblogs.com/wujin/p/6121754.htmlsql

http://www.jianshu.com/p/799252156379性能

http://lxw1234.com/archives/2015/04/20.htm