拉链表须知

1、拉链表由来
拉链表是一种维护历史状态,以及最新状态数据的一种表。拉链表根据拉链粒度的不同,去除了一部分不变的记录,通过拉链表可以很方便的还原出拉链时点的客户记录,实际上相当于快照。
2、拉链表的特征
1)记录一个事物从开始,一直到当前状态的所有变化的信息;
2)每次上报的都是历史记录的最终状态,是记录在当前时刻的历史总量;
3)当前记录存的是当前时间之前的所有历史记录的最后变化量(总量);
4)存量一般设计成拉链表(月报 - 常用、日报);
5)关链时间可以是3000年,9999等比较大的年份,例如[2022-07-01,9999-12-31]
表示连续的状态,因为开始时间为2022-07-01,闭合时间为未知;
3、拉链表适用的场景

  1. 数据量比较大。
  2. 表中的部分字段会被更新,比如用户的地址,银行利率,订单的状态等。
  3. 需要查看某一个时间点或者时间段的历史快照信息,比如,查看利率在历史某一个时间点的状态。
  4. 变化的比例和频率不是很大,比如,总共有1000万的会员,每天新增和发生变化的有10万左右。
  5. 如果对这边表每天都保留一份全量,那么每次全量中会保存很多不变的信息,对存储是极大的浪费;
    拉链历史表,既能满足反应数据的历史状态,又可以最大程度的节省存储。
    4.实例
    现有一份公司内部员工表,有信息会发生更改,现依据结束时间为分区条件做成拉链表
create table if not exists test.a_hist
(    id STRING COMMENT 'id'
     ,start_dt string COMMENT'拉链开始时间'
     ,name STRING COMMENT '名字'
     ,dep_id STRING COMMENT '部门id'
     ,type STRING COMMENT '是否在职|Y,N'
) comment '拉链表'
  partitioned by (end_dt string comment '分区')
  stored as orc
  tblproperties ('orc.compress' = 'SNAPPY')
;
 -- 1.取当天全量比对3000-12-31记录取出纯增量&有变更数据
    drop table IF EXISTS test_tmp.tmp_a_inc;
    CREATE table test_tmp.tmp_a_inc 
    stored as orc
    as
    SELECT
                 p1.id
                ,'${last_date}' as start_dt
                ,p1.name
                ,p1.dep_id 
                ,p1.type 
        from  test_dim.a_df p1
       where  p1.pt_d = '${last_date}'
         AND  P1.biz_id IS NOT NULL
         and not EXISTS 
             (
                 SELECT
                        1
                   from test_dim.a_hist p2
                   WHERE  p2.end_dt = '3000-12-31'
                     AND  p2.id IS NOT NULL
                     AND  p1.id = p2.id
                    and  coalesce(p1.name,'-1') = coalesce(p2.name,'-1')
                    and coalesce(p1.dep_id,'-1') = coalesce(p2.dep_id,'-1')
                    and coalesce(p1.type,'-1') = coalesce(p2.type,'-1')                  
             )
;
 -- 2.3000-12-31中未发生变更记录
drop table IF EXISTS test_tmp.tmp_a_stock;
CREATE table test_tmp.tmp_a_stock 
stored as orc
as
SELECT 
                 p1.id
                ,p1.start_dt
                ,p1.name
                ,p1.dep_id 
                ,p1.type 
FROM test_dim.a_hist p1
   WHERE    p1.end_dt = '3000-12-31'
     AND    P1.id IS NOT NULL
     AND    not EXISTS (select 1 from test_tmp.tmp_a_inc p2 where p1.id = p2.id)
  ;
  -- 3.3000-12-31中发生变更记录
  drop table IF EXISTS test_tmp.tmp_a_upd;
  CREATE table test_tmp.tmp_a_upd 
  stored as orc
  as
  SELECT
                 p1.id
                ,p1.start_dt
                ,p1.name
                ,p1.dep_id 
                ,p1.type 
    from    servyou_dim.a_hist p1
   WHERE    p1.end_dt = '3000-12-31'
     AND    P1.id IS NOT NULL
     AND    P1.START_DT <> '${last_date}'
     AND    EXISTS (select 1 from test_tmp.tmp_a_inc p2 where p1.id = p2.id)
  ;
-- 将发生变动的历史记录插入end_dt = '${last_date}'分区中
-- 将新的3000-12-31记录插入end_dt = '3000-12-31'分区中
	insert overwrite table test.a_hist partition(end_dt)
    select  *
      FROM  (
	select
            *
            ,'${last_date}' as end_dt
	  from  test_tmp.tmp_a_upd
    union all
	SELECT  *
            ,'3000-12-31' as end_dt
	  from  test_tmp.tmp_a_inc
    union all
	select  *
            ,'3000-12-31' as end_dt
	  from  test_tmp.tmp_a_stock
            ) x 
    distribute by x.end_dt;

last_date等同于yesterday
那么假设前一天数据有误,而代码也已经跑完该怎么恢复呢

end_dt = '${last_date}' 的记录需要还原至3000-12-31分区中
end_dt = '3000-12-31' 且 start_dt = '${last_date}'的记录需要剔除
drop table if exists test_tmp.tmp_a_recover;
  create table test_tmp.tmp_a_recover 
  stored as orc
  as
  select
                 p1.id
                ,p1.start_dt
                ,p1.name
                ,p1.dep_id 
                ,p1.type 
    from    test_dim.a_hist p1
   WHERE    p1.end_dt = '${last_date}'
union ALL
  select
                 p1.id
                ,p1.start_dt
                ,p1.name
                ,p1.dep_id 
                ,p1.type 
    from    test_dim.a_hist p1
   WHERE    p1.end_dt = '3000-12-31'
     AND    p1.start_dt <> '${last_date}'
  ;

  INSERT overwrite table test.a_hist partition(end_dt = '3000-12-31')
  select
          *
    FROM  test_tmp.tmp_a_recover
  ;

  ALTER table test.a_hist drop partition(end_dt = '${last_date}')
  ;

先执行上面的代码后,再去执行最上面的代码

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值