企业数仓拉链表制作

一、拉链表定义

记录每条信息的生命周期,一旦一条记录的生命周期结束,就重新开始一条新的记录,并把当前日期放入生效开始日期。如果当前信息至今有效,在生效结束日其中填入一个极大值(如:9999-99-99)

生效日期 <= 某个日期 且 >=某个日期

二、为什么要做拉链表

拉链表适合于:数据会发生变化,但是大多数的数据是不变的,即缓慢变化维
比如: 订单信息从未支付、已支付、未发货、已完成等状态经历了一周,大部分时间是不变化的,如果数据量规模较大,按照每日全量的方式保存效率很低,如:1亿用户 * 365天,每天一份用户信息(每日全量效率低)。

三、拉链表形成过程

通过生效日期 <= 某个日期 且 >=某个日期,得到某个时间点的全量切片。
1)拉链表数据

拉链表数据

2)例如:获取2019-01-01的历史切片:select * from order_info where start_date<='2019-01-01' and end_date>='2019-01-01';

2019-01-01

3)例如:获取2019-01-02的历史切片:select * from order_info where start_date<='2019-01-02' and end_date>='2019-01-02';

2019-01-02
拉链表形成过程

四、拉链表制作流程图

将首日全部数据作为初始拉链表dwd_order_info_his;第二日,创建临时拉链表和第二日变化数据(新增和变化)制作成一个新的拉链表,以此类推。

五、拉链表制作实战

5.1初始化拉链表

1)建立拉链表

drop table if exists dwd_order_info_his;
create external table dwd_order_info_his(
    `id` string COMMENT '订单编号',
    `total_amount` decimal(10,2) COMMENT '订单金额',
    `order_status` string COMMENT '订单状态',
    `user_id` string COMMENT '用户id' ,
    `payment_way` string COMMENT '支付方式',
    `out_trade_no` string COMMENT '支付流水号',
    `create_time` string COMMENT '创建时间',
    `operate_time` string COMMENT '操作时间',
    `start_date`  string COMMENT '有效开始日期',
    `end_date`  string COMMENT '有效结束日期'
) COMMENT '订单拉链表'
stored as parquet
location '/warehouse/gmall/dwd/dwd_order_info_his/'
tblproperties ("parquet.compression"="snappy");

初始日期以2019-02-13为例。
2)初始化拉链表
从ods层直接将ods_order_info 所有数据拿过来

insert overwrite table dwd_order_info_his
select
    id,
    total_amount,
    order_status,
    user_id,
    payment_way,
    out_trade_no,
    create_time,
    operate_time,
    '2019-02-13',
    '9999-99-99'
from ods_order_info oi
where oi.dt='2019-02-13';

5.2 制作当日变动数据(新增和修改),每日执行

(1)如何获取每日变动表

  • 表内有创建时间和变动时间,可直接获取
  • 表内没有创建时间和变动时间,利用第三方工具监控比如canal,监控MySQL的实时变化进行记录
  • 业务数据库提供变动流水

我们dwd_order_info在我们的dwd层是根据每日partition的,所以我们根据日期倒过来的数据就是新增变动明细表。

5.3先合并变动信息,再追加新增信息,插入到临时拉链表中

1)建立临时表

drop table if exists dwd_order_info_his_tmp;
create table dwd_order_info_his_tmp( 
    `id` string COMMENT '订单编号',
    `total_amount` decimal(10,2) COMMENT '订单金额', 
    `order_status` string COMMENT '订单状态', 
    `user_id` string COMMENT '用户id' ,
    `payment_way` string COMMENT '支付方式',  
    `out_trade_no` string COMMENT '支付流水号',  
    `create_time` string COMMENT '创建时间',  
    `operate_time` string COMMENT '操作时间',
    `start_date`  string COMMENT '有效开始日期',
    `end_date`  string COMMENT '有效结束日期'
) COMMENT '订单拉链临时表'
stored as parquet
location '/warehouse/gmall/dwd/dwd_order_info_his_tmp/'
tblproperties ("parquet.compression"="snappy");

2)导入脚本


insert overwrite table dwd_order_info_his_tmp
select * from 
(
select 
id,
    total_amount,
    order_status,
    user_id,
    payment_way,
    out_trade_no,
    create_time,
    operate_time,
    '2019-02-14' start_date,
    '9999-99-99' end_date
from dwd_order_info where dt='2019-02-14'

union all 
select oh.id,
    oh.total_amount,
    oh.order_status,
    oh.user_id,
    oh.payment_way,
    oh.out_trade_no,
    oh.create_time,
    oh.operate_time,
    oh.start_date,
    if(oi.id is null, oh.end_date, date_add(oi.dt,-1)) end_date
from dwd_order_info_his oh left join 
     (
select
*
from dwd_order_info
where dt='2019-02-14'
) oi
     on oh.id=oi.id and oh.end_date='9999-99-99'  
)his 
order by his.id, start_date;

解析:


临时拉链表数据导入

订单变化表 union all (初始拉链表dwd_order_info_his left join 订单变化表dwd_order_info)

为什么要加

if(oi.id is null, oh.end_date, date_add(oi.dt,-1)) end_date

oi 订单变化表, oh 初始拉链表
因为订单变化表中id在初始拉链表中不存在,为null,即为新增数据,则这条数据的结束日期就是该条数据的结束日期,不需要改变。
订单变化表中id在初始拉链表中存在,不为null,即为需要变化数据,则这条数据的添加到拉链表中时,要将id相同的上一条数据的日期的9999-99-99改成date_add(oi.dt,-1),即新的这条数据的前一天的日期。


为什么要找出这条9999-99-99的数据?
因为 相同id的数据有多条的时候,会将所有该id的数据的结束日期修改date_add(oi.dt,-1),例如:

id    status    start_date     end_date
1      1        2019-01-10    2019-02-13
1      2        2019-02-13    9999-99-99

如果此时来了一条数据:" 1 3 2019-01-10 2019-02013",我们只能修改“1 2 2019-02-13 9999-99-99”不能修改“1 1 2019-01-10 2019-02-13”


3)把临时表覆盖给拉链表

insert overwrite table dwd_order_info_his 
select * from dwd_order_info_his_tmp;

你可能感兴趣的:(企业数仓拉链表制作)