基于多表增量同步的拉链表实现

目录

前言(屁话):

方法实现:

利用with关键字:

提取公因式:

提取公倍式:

多级full join数据:

拆分任务:

尾声:


前言(屁话):

        其实一开始我是在做拉链表时遇到了一个难点,就是当你的增量数据如果要拿到最新数据的话,就得进行一个多表的全表扫描,然后进行排序。当时一个60w条用户的SQL任务,居然需要18分钟的时间(在Maxcompute上),这令我不禁疑惑自己的SQL能力,于是我进行了改进:

方法实现:

        由于我开始无法优化拉链表任务,上网搜了不少关于拉链表实现的文章与博客,发现通通都是条件过于简单,源表只有一张的情况(要不就是抄别人的文章,要不就是乱说一通而且自己也没明白原理的,看了都浪费时间),于是我另辟蹊径打算通过自己的方式进行任务优化,以下是我的总结:拉链表的实质是区分最新数据与过期数据的问题,可以通过以下三个方法优化任务。

利用with关键字:

        在你需要反复的利用某表时,不妨试试with关键字(大于一次利用某表都可以使用)。这样可以大幅减少开发代码以及运行时间。

提取公因式:

        这里适合的场景是你SQL逻辑相近、且字段相同的语句。如下所示,那么表一就是可以写在with中的语句,要用到表二表三时,只需要添加对应的条件即可。

-- 表一

select 
    id,
    name,
    class
from student

-- 表二

select 
    id,
    name,
    class 
from student
where class='语文'

-- 表三

select 
    count(*)
from(
    select 
        id,
        name,
        class 
    from student
)t1
group by class
where id>100

提取公倍式:

        适用于SQL语句挑选的字段来源于同一张表的场景。

-- 表一
select 
    id,
    name,
    class,
    teacher
from student


-- 表二

select 
    name,
    class
from student


-- 表三

select 
    id,
    class,
    grades
from student

如上所示,显然三张表字段都不同,但都是来自同一张表,于是我们可以在with里将所有字段的并集进行筛选。

select 
    id,
    name,
    class,
    grades,
    teacher
from student

当然逻辑复杂时,两种方式应该混合使用,可以保证效率的最高!!!(建议自行摸索锻炼一下)

通过with方式,我将拉链表任务的运行时间缩短至几分钟(越多重复筛选,效果越明显)。

多级full join数据:

        数据处理通常没有想象中的简单,往往数据库中的表比较零散,需要多表join后才能放入维度表,而且在用户表这种大体量数据的情况下,增量同步的方式肯定更多,且在准实时如一小时一更新的场景下,难免出现任务复杂但要求时效性的情况。这时,如果对多分区、大体量数据进行全表扫描,with其实只是治标不治本,怎么避免对增量同步的表全表扫描是一个关键

        通常有些字段只需要对旧数据进行一次full join,这种字段只需要我们直接对最新分区进行full join获取最新数据即可

select
    nvl(new.id,old.id),
    nvl(new.name,old.name),
    nvl(new.class,old.class),
    nvl(new.phone,old.phone),
    nvl(new.create_time,old.create_time),
    nvl(new.birthday,old.birthday),
    father,
    mother
-- 取旧数据
from (
   select 
        id,
        name,
        class,
        phone,
        father,
        mother,
        create_time,
        birthday
    from dim_student    
    where pt='99990101' 
)old
-- 取最新数据
full join (
    select 
        id,
        name,
        class,
        phone,
        create_time,
        birthday
    from ods_student
    where pt='最新分区'
)new
on new.id=old.id

如上所示,我们可以直接获取到部分字段的最新数据,但是有些数据可能需要通过最新数据再次关联其他表才能得到,我们对其再次进行full join,每一次full join可以解决同一层级多个表关联这样就解决了增量更新带来的全表扫描问题,大幅减少任务时间!!

select
    new.id,
    old.id,
    new.name,
    old.name,
    new.class,
    old.class,
    new.phone,
    old.phone,
    new.create_time,
    old.create_time,
    new.birthday,
    old.birthday,
    t1.father,
    t2.father,
    t1.mother,
    t3.mother
from (
    select
        new.id,
        old.id,
        new.name,
        old.name,
        new.class,
        old.class,
        new.phone,
        old.phone,
        new.create_time,
        old.create_time,
        new.birthday,
        old.birthday,
        father,
        mother
    -- 取旧数据
    from (
       select 
        id,
        name,
        class,
        phone,
        father,
        mother,
        create_time,
        birthday
        from dim_student    
        where pt='99990101' 
    )old
    -- 取最新数据
    full join (
        select 
        id,
        name,
        class,
        phone,
        create_time,
        birthday
        from ods_student
        where pt='最新分区'
    )new
    on new.id=old.id
)t1
full join(
    select
        id,
        father
    from ods_father
    where pt='最新分区'
)t2
on nvl(new.id,old.id)=t2.id
full join(
    select
        id,
        mother
    from ods_mother
    where pt='最新分区'
)t3
on nvl(new.id,old.id)=t3.id

拆分任务:

        当然你也可以采取“逃避性”的拆分任务,也就是多表分装数据:将一个拉链表变成多个拉链表,同时运行,这样不仅逻辑清晰,而且运行起来是相当的快(几个小任务绝对比一个大任务要更加的轻松)。但并不值得推荐,因为通常一个维度的信息在一起查询更加便捷,当然如果有更小的粒度的话还是可以拆分的,比如用户表可能有多个体系,每个体系提供的字段可能都不同,这时你可以将其拆分成一个统一的基础信息表,和各个维度的细分信息表应对不同的需要。

尾声:

        还是一句话,没有最好的方法,只有最合适的套路,根据自己的场景定制最为合适的拉链表策略才是我们值得做的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值