拉链,通俗来讲即打开和关闭数据,设计表的时候添加 start_date 和 end_date 两个字段,数据更新时,通过修改 END_DATE 来设置数据的有效时间。
数据的拉链表只存一份全量数据,其余都是增量数据,查询时使用 start_date 和 end_date 作为约束条件来筛选某日的数据快照。同时可以节省存储空间,记录历史变化。
哪些情况下使用拉链表
- 数据量比较大;
- 表中的部分字段会被更,如销售部门,产品的描述信息,订单的状态等等;
- 需要查看某一个时间点或者时间段的历史快照信息,比如,查看某销售在历史某段时间内的归属部门,再比如,统计某一个用户在过去某段时间内,有更新过几次等;
- 变化的比例和频率不是很大,比如,总共有1000万的会员,每天新增和发生变化的有10万左右,如果对这边表每天都保留一份全量,那么每次全量中会保存很多不变的信息,对存储是极大的浪费。
综上所述:引入"拉链历史表",既能满足反应数据的历史状态,又可以最大程度的节省存储。
--提取全量最新数据
drop table if exists tmp.tmp_zip_one;
create table tmp.tmp_zip_one as
select saler_id,saler_name,shop_id,shop_name
from table_name
where dt='20201015';
--备份之前数据状态,dim_zip为目标拉链维表,分区dp有两个,分别为active(当前)和his(历史)
drop table if exists tmp.tmp_zip_two;
create table tmp.tmp_zip_two as
select * from dimdb.dim_zip;
--更新active分区
insert overwrite table dimdb.dim_zip partition(dp='active')
-- 不变的
select
ta.saler_id,
ta.saler_name,
ta.shop_id,
ta.shop_name,
ta.start_date,
ta.end_date
from tmp.tmp_zip_one ta
join tmp.tmp_zip_two tb
on ta.saler_id = tb.saler_id
and tb.dp = 'active'
where ta.shop_id=tb.shop_id
union all
-- 新增的
select
ta.saler_id,
ta.saler_name,
ta.shop_id,
ta.shop_name,
date_sub(current_date(), 1) as start_date,
'9999-01-01' as end_date
from tmp.tmp_zip_one ta
left join tmp.tmp_zip_two tb
on ta.saler_id = tb.saler_id
and tb.dp = 'active'
where tb.saler_id is null
union all
-- 改变的,改变后
select
ta.saler_id,
ta.saler_name,
ta.shop_id,
ta.shop_name,
date_sub(current_date(), 1) as start_date,
'9999-01-01' as end_date
from tmp.tmp_zip_one ta
join tmp.tmp_zip_two tb
on ta.saler_id = tb.saler_id
and tb.dp = 'active'
where ta.shop_id!= tb.shop_id;
--更新历史分区
insert overwrite table dimdb.dim_zip partition(dp='his')
-- 改变的, 改变前
select
tb.saler_id,
tb.saler_name,
tb.shop_id,
tb.shop_name,
tb.start_date,
date_sub(current_date(), 2) as end_date
from tmp.tmp_zip_one ta
join tmp.tmp_zip_two tb
on ta.saler_id = tb.saler_id
and tb.dp = 'active'
where ta.shop_id!= tb.shop_id
union all
-- 最新删除的
select
tb.saler_name,
tb.shop_id,
tb.shop_name,
tb.start_date,
date_sub(current_date(), 2) as end_date
from tmp.tmp_zip_two tb
left join tmp.tmp_zip_one ta
on ta.saler_id = tb.saler_id
where tb.dp = 'active'
and ta.saler_id is null
union all
-- 之前删除、改变的
select
tb.saler_name,
tb.shop_id,
tb.shop_name,
tb.start_date,
tb.end_date
from tmp.tmp_zip_two tb
where tb.dp = 'his';