拉链表概念
拉链表,记录每条信息的生命周期,一旦一条记录的生命周期结束,就重新开始一条新的记录,并把当前日期放入生效开始日期。如果当前日期至今有效,在生效结束日期中填入一个极大值,如9999-99-99。
拉链表适合于数据会发生变化,但是大部分是不变的。只在数据变化的时候进行记录,其他时候不做处理,减少了处理的数据量。
拉链表制作
下面以订单表2019-02-13和2019-02-14两天的数据为例,展示拉链表的制作过程。
1 建立一个订单信息的拉链表
这个拉链表与ODS层和DWD层的订单表字段相比,增加了两个字段,即数据的有效开始日期和有效结束日期。
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那天的数据。拉链表的数据,从ODS层或DWD导入都可以(做成脚本)。
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';
2 建立一个临时拉链表,结构与正式拉链表一致
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");
临时拉链表数据导入
①union前面的数据是2019-02-14的数据,来源于DWD层,前面说过,订单表的同步策略包括每日增量和变化。因此14号的数据即包括14号新产生的订单信息,也可能包括13号的在14号状态有变化的订单。
②union后面的查询,就是将拉链表中的数据去左连2019-02-14的数据,并将生效日期为9999-99-99的数据(即以前状态为最新的数据)的有效结束日期改为2019-02-14的前一天。
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;