首页 > 其他分享 >离线数仓中的拉链表

离线数仓中的拉链表

时间:2023-02-24 21:11:41浏览次数:50  
标签:数仓 01 old 拉链 离线 time date new id

拉链表

什么是拉链表?

​ 拉链表,记录每条信息的生命周期,一旦一条记录的生命周期结束,就重新开始一条新的记录,并把当前日期放入生效的开始日期。(就是在原来表的基础上,加上创建时间/开始时间/操作时间/结束时间,能保证看出记录的变化过程就行了)

如果当前消息至今有效,在生效结束日期中填入一个极大值(如:9999-12-31)

为什么要做拉链表

拉链表适合于:数据会发生变化,但是变化频率不高的维度,常作为增量同步表

比如:用户信息会发生变化,但是每天变化的比例不高。如果数据量有一定规模,按照每日全量的方式保存效率很低。比如:一亿用户*365天,每天一份用户信息(做每日全量效率低)

每日全量表:

用户ID 姓名 手机号码 dt
1 张三 136****9999 2023-01-25
1 张三 136****9999 2023-01-26
1 张三 136****9999 2023-01-27
... ... ... ...
1 张三 136****9999 2023-01-30
1 张三 157****1111 2023-01-31

拉链表:

用户ID 姓名 手机号码 开始日期 结束日期
1 张三 136****9999 2023-01-25 2023-01-30
1 张三 157****1111 2023-01-31 9999-12-31

通过上面,可以看出,拉链表大大降低的存储内容,也使数据变化过程变得更加明了

如何使用拉链表

以用户维度表为例

在数仓项目当中,拉链表常常采用增量同步策略,增量同步策略主要有两种方式,一种使用过binlog,另一种是通过查询(当然,首日直接全量同步就行了)

通过binlog的方式实现增量同步

采用MaxWell同步工具的话,因为其是支持断点续传的,会把1天中的中间状态也记录到,所以还要考虑过滤数据的因数

第一步:过滤数据的中间状态,得出一天中最终的状态

  • 获取ods层最新数据,然后通过row_number()函数按id分组、时间降序,取行号为1的数据即可过滤出一天中最终的状态,最后再查询一遍,赋予开始时间(当前时间)和结束时间(最大时间)-- 新表

第二步:昨日用户维度表数据(分区为9999-12-31)与新表数据进行关联

  • 查找该拉链表的最新分区数据(往往找最大时间分区的数据就行了)通过full outer join与第一步得出的表按id相等条件进行关联,得到了昨天与今天的全部数据。

第三步:判断

  • 开启动态分区,通过if或者nvl函数,判断新表id是否为空,如果为空就为旧表id对应的数据,否则返回自己id对应的数据。-- 得出新增数据
  • union all再查询一次,筛选出新表id旧表id不为null的数据,修改结束时间为当前时间减一。 -- 得出历史数据

案例:

with
tmp as
(
    select
        old.id old_id,
        ...
        old.create_time old_create_time,
        old.operate_time old_operate_time,
        old.start_date old_start_date,
        old.end_date old_end_date,
        new.id new_id,
        ...
        new.create_time new_create_time,
        new.operate_time new_operate_time,
        new.start_date new_start_date,
        new.end_date new_end_date
    from
    (
        select
            id,
            ...
            create_time,
            operate_time,
            start_date,
            end_date
        from dim_user_zip
        where dt='9999-12-31'
    )old
    full outer join
    (
        select
            id,
            ...
            create_time,
            operate_time,
            '2023-01-25' start_date,
            '9999-12-31' end_date
        from
        (
            select
                data.id, -- ods层的数据存储采用结构体,根据自己情况改变
                ...
                data.create_time,
                data.operate_time,
                row_number() over (partition by data.id order by ts desc) rn
            from ods_user_info_inc
            where dt='2023-01-25'
        )t1
        where rn=1
    )new
    on old.id=new.id
)
insert overwrite table dim_user_zip partition(dt)
select
    if(new_id is not null,new_id,old_id),
    ...
    if(new_id is not null,new_create_time,old_create_time),
    if(new_id is not null,new_operate_time,old_operate_time),
    if(new_id is not null,new_start_date,old_start_date),
    if(new_id is not null,new_end_date,old_end_date),
    if(new_id is not null,new_end_date,old_end_date) dt
from tmp
union all
select
    old_id,
    ...
    old_create_time,
    old_operate_time,
    old_start_date,
    cast(date_add('2023-01-25',-1) as string) old_end_date,
    cast(date_add('2023-01-25',-1) as string) dt
from tmp
where old_id is not null
and new_id is not null;

通过查询的方式实现增量同步

这与binlog类似,只是少了过滤数据的步骤

标签:数仓,01,old,拉链,离线,time,date,new,id
From: https://www.cnblogs.com/Mr-Sponge/p/17153131.html

相关文章