维度建模之缓慢渐变维

维度建模之缓慢渐变维

在从 OLTP 业务数据库向 DW 数据仓库抽取数据的过程中,特别是第一次导入之后的每一次增量抽取往往会遇到这样的问题:业务数据库中的一些数据发生了更改,到底要不要将这些变化也反映到数据仓库中?在数据仓库中,哪些数据应该随之变化,哪些可以不用变化?考虑到这些变化,在数据仓库中的维度表又应该如何设计以满足这些需要。

  1. 每天保存当前数据的全量快照数据,该方案适合数据量较小的维度,使用简单的方式保存历史状态

  2. 在维表中添加关键属性值的历史字段,仅保留上一个的状态值

  3. 拉链表

什么是缓慢渐变维?

维度数据会随着时间发生变化,变化速度比较缓慢,这种维度数据通常称作缓慢渐变维;由于数据仓库需要追溯历史变化,尤其是一些重要的数据,所以历史状态也需要采取一定的措施进行保存。

比如顾客的联系方式,手机号码等信息可能随着顾客的所在地的更改发生变化,比如商品的价格在不同时期有上涨和下降的变化。那么在业务数据库中,很自然的就会修改并马上反映到实际业务当中去。但是在数据仓库中,其数据主要的特征一是静态历史数据,二是少改变不删除,三是定期增长,其作用主要用来数据分析。

拉链表

当数据发生变化时,将旧数据置为失效,将更改后的数据当作新的记录插入到维度表中,并开始生效,这样能够记录数据在某种粒度上的变化历史。

维度拉链表:

如下所示:

在这里插入图片描述
其中start_date为生效时间,end_date为失效时间。查询有效数据如下语句

Select * from user where start_date<= 2018-05-22 and end_date>= 2018-05-22

因为是对维度表做拉链,所以同一个维度实体必然存在多条记录,此时维度表的原子性主键就不存在了,可以使用添加代理键的方式实现维度表和事实表的关联。

事实表装载代理键(含缓慢渐变维)

如下是订单事实表和用户维度表(含代理键):
在这里插入图片描述
事实表中历史的用户维度ID不会发生变化,所以事实表的代理键加载仅发生在新增数据上。

-- 事实表装载代理键
select 
    ta.*,
    tb.uid
from 
    fact_order as ta
join (
    select 
        *
    from
        dim_user as tb
    where '${bizDate}' >= start_date and '${bizDate}' <= end_date
) as tb 
on ta.id = tb.id

注意:
${bizDate}为时间限定,每天增量表可取到当天。如20191204...

代理键是维度建模中极力推荐的方式,它的应用能有效的隔离源端变化带来的数仓结构不稳定问题,同时也能够提高数据检索性能但是如所见,代理键维护代价非常高,尤其是数据装载过程中,对事实表带来了较大的影响,在基于hive的数据仓库建设影响更加严重,比如代理键的生成、事实表中关联键的装载、不支持非等值关联等问题,带来ETL过程更加复杂故,在大数据体系下,谨慎使用代理键,同时对于缓慢渐变维场景,可以考虑用空间换取时间,每天保留维表全量快照;但这样会带来存储成本,根据实际情况衡量

事实拉链表:

当事实表数据量大,但数据是缓慢变化,需要跟踪历史状态,和缓慢渐变维类似,需要用到事实拉链表。

如:信用卡场景,由于用户的信用额度、已用额度存在缓慢的变化,又需要跟踪变化的记录,设计相关事实表。

​ 源数据包括(credit_amount):用户id、卡id、额度、已用额度、剩余额度、创建时间、更新时间

  • 增量事实拉链表

    -- 伪代码仅供参考
    -- 1.增量采集数据
    insert into s_credit_amount
    select 
        *
    from  credit_amount
        where updated_time>='2019-12-01 00:00:00'
    -- 2.dwd层拉链表设计 d_credit_amount_l(l表示拉链表)
    drop table if exists tmp_credit_amount;
    create table tmp_credit_amount as 
    select 
        *
    from (
        select
            ta.card_id, -- 卡ID
            ta.user_id, -- 用户ID
            ta.amount, -- 额度
            ta.used_amount, -- 已用额度
            ta.created_time, -- 创建时间
            ta.updated_time, -- 更新时间
            ta.start_date, -- 拉链表(开始时间)
            (
             case 
                when tb.card_id is not null and ta.end_date>'2018-06-01' then '2018-05-31' 
                else ta.end_date 
             end
            ) as end_date, -- 拉链表(失效时间)
            load_time -- 方便排查问题
        from
            d_credit_amount_l as ta
        left join
        		s_credit_amount as tb
        on ta.card_id=tb.card_id
    
        union all -- union 发生变化的数据
    
        select 
            ta.card_id, -- 卡ID
            ta.user_id, -- 用户ID
            ta.amount, -- 额度
            ta.used_amount, -- 已用额度
            ta.created_time, -- 创建时间
            ta.updated_time, -- 更新时间
            '2019-10-04' as start_date, -- 拉链表(开始时间)
            '9999-12-31' as end_date, -- 拉链表(失效时间)
            unix_timestamp() as load_time  -- 数据生成时间
        from
            s_credit_amount as ta
    )tmp
    
    insert overwrite into d_credit_amount_l
    select * from tmp_credit_amount;
    
    备注:
    	首先查询增量数据中变化的数据更改end_date置为失效状态,再union关联新增数据。
    	
    
  • 全量事实拉链表

    -- 伪代码仅供参考
    select
        ta.*
    from(
        select
            ta.card_id,
            ta.user_id,
            ta.amount,
            ta.used_amount,
            ta.created_time,-- 捕获数据变化
            md5(concat(card_id,user_id,amount,used_amount,created_time)) as md5_flag
        from 
            d_credit_amount_d as ta 
        where dt='2019-12-05'
        )ta
    left join(
        select
            ta.card_id,
            ta.user_id,
            ta.amount,
            ta.used_amount,
            ta.created_time,
            md5_flag
        from 
            d_credit_amount_d as ta 
        where dt='2019-12-04'
        )tb
    on ta.card_id=tb.card_id
    where ta.md5!=tb.md5 or tb.card_id is null
    
    备注:
    	可以根据重要属性,进行md5加密确认唯一一条数据(可根据MD5判断改变数据)

    关注公众号 数据工匠记 ,专注于大数据领域离线、实时技术干货定期分享!个人网站 www.lllpan.top
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/lp284558195/article/details/112267996