数仓中的全量表,增量表,拉链表,流水表,快照表 机会终于来了系列
作者:互联网
写在前面
先简单说明一下这几种表形态的定义:
全量表:每天的所有写最新状态的数据
1、有无变化,都要报
2、每次上报的数据都是所有的数据(变化的+没有变化的)
增量表:新增的数据
1、增量表,只报变化量,无变化不用报
拉链表:
1、记录一个事物从开始,一直到当前状态的所有变化的信息
2、拉链表每次上报的都是历史记录的最终状态,是记录在当前时候的历史总量
流水表:对于表的每一个修改都会记录,可以用户反映实际记录的变更
1、拉链表通常是对账户信息的历史变动进行处理保留的结果,流水表是对每天的交易形成的历史
2、流水表用于统计业务相关情况,拉链表用于统计账户及客户的情况
快照表:数据包含前一天的全量数据,按照每一天进行分区
理清每一种表形态的定义是很重要的额,因为不同场景定义不同类型的表能够极大提升数据查询效率并且最大程度节省存储空间。
ps:我以银行账户余额为例
数据准备
第一天 12月1号数据
liuge36,1000,2020-12-01 12:12:10,2020-12-01 12:12:10
shishishi,2000,2020-12-01 14:23:10,2020-12-01 14:23:10
zkk,3000,2020-12-01 16:12:10,2020-12-01 16:12:10
第二天 12月2号数据
liuge36,2000,2020-12-01 12:12:10,2020-12-02 12:12:10
shishishi,2000,2020-12-01 14:23:10,2020-12-01 14:23:10
zkk,2000,2020-12-01 16:12:10,2020-12-02 16:12:10
lhh36,5000,2020-12-02 16:12:10,2020-12-01 16:12:10
lhh37,5000,2020-12-02 16:12:10,2020-12-01 16:12:10
对比第2天数据比第1天数据发现,第二天新增了 lhh36 和 lhh37 两个用户数据,
同时,liuge36的账户余额变成了2000元,zkk的账户余额也变成了2000元 ,
shishishi 用户无变化。
全量表
每天的所有的最新状态的数据。
1、全量表,有无变化,都要报
2、每次上报的数据都是所有的数据(变化的 + 没有变化的)
12月1号数据全量抽取到ods层
create database lgdw_ods;
create database lgdw_dwd;
create table lgdw_ods.user_account_20201201(
user_name string COMMENT '用户名'
,balance string COMMENT '余额'
,create_time timestamp COMMENT '创建时间'
,update_time timestamp COMMENT '更新时间'
) COMMENT '账户余额表MMDD'
row format delimited fields terminated by ','
;
load data local inpath '/users/liuge36/desktop/liugedata/1201.txt' overwrite into table lgdw_ods.user_account_20201201;
//全量分区表
create table lgdw_dwd.user_account_df(
user_name string COMMENT '用户名'
,balance string COMMENT '余额'
,create_time timestamp COMMENT '创建时间'
,update_time timestamp COMMENT '更新时间'
) COMMENT '账户余额表'
partitioned by (dw_etl_dt string)
row format delimited fields terminated by ','
;
把 lgdw_ods.user_account_20201201全量数据 插到 dwd层 2020-12-01 分区
insert overwrite table lgdw_dwd.user_account_df partition(dw_etl_dt = '2020-12-01')
select
user_name
,balance
,create_time
,update_time
from lgdw_ods.user_account_20201201
;
1202数据再 抽取到 ods 层
create table lgdw_ods.user_account_20201202(
user_name string COMMENT '用户名'
,balance string COMMENT '余额'
,create_time timestamp COMMENT '创建时间'
,update_time timestamp COMMENT '更新时间'
) COMMENT '账户余额表MMDD'
row format delimited fields terminated by ','
;
load data local inpath '/users/liuge36/desktop/liugedata/1202.txt' overwrite into table lgdw_ods.user_account_20201202;
把 lgdw_ods.user_account_20201202 全量数据 插到 dwd层 2020-12-02 分区
insert overwrite table lgdw_dwd.user_account_df partition(dw_etl_dt = '2020-12-02')
select
user_name
,balance
,create_time
,update_time
from lgdw_ods.user_account_20201202;
全量抽取,每个分区保留历史全量快照。
增量表
增量表:新增数据,增量数据是上次导出之后的新数据。
1、记录每次增加的量,而不是总量;
2、增量表,只报变化量,无变化不用报
3、业务库表中需有主键及创建时间,修改时间
增量表
12月1号 全量数据 抽取到ods层(同上)
12月2号 增量数据 抽取到ods层,即相比1201新增和更新的数据
create table lgdw_dwd.user_account_di(
user_name string COMMENT '用户名'
,balance string COMMENT '余额'
,create_time timestamp COMMENT '创建时间'
,update_time timestamp COMMENT '更新时间'
) COMMENT '账户余额表'
partitioned by (dw_etl_dt string)
row format delimited fields terminated by ','
;
把 lgdw_ods.user_account_20201201全量数据 插到 dwd层 2020-12-01 分区
insert overwrite table lgdw_dwd.user_account_di partition(dw_etl_dt = '2020-12-01')
select
user_name
,balance
,create_time
,update_time
from lgdw_ods.user_account_20201201
;
lgdw_dwd.user_account_di 表12月1号的分区数据与 lgdw_ods.user_account_20201202 增量抽取的数据合并,有2种方案;
方案a.两个表通过主键关联,dwd表存在并且ods1202表不存在的数据(历史数据)
union all 一下 lgdw_ods.user_account_20201202 表所有的数据(新数据)
即全量数据插入到dwd表的12月2号的分区
insert overwrite table lgdw_dwd.user_account_di partition (dw_etl_dt = '2020-12-02')
select
t1.user_name
,t1.balance
,t1.create_time
,t1.update_time
from lgdw_dwd.user_account_di t1
left join
lgdw_ods.user_account_20201202 t2
on t1.user_name = t2.user_name
where t1.dw_etl_dt = '2020-12-01'
and t2.user_name is null
union all
select
user_name
,balance
,create_time
,update_time
from
lgdw_ods.user_account_20201202;
方案b.两个表数据union all一下,再根据user_name去重(根据order分组,更新时间降序,取第一条)
同样,需要先把第一天的数据存入dwd1201分区,然后直接与ods1202数据union all
insert overwrite table lgdw_dwd.user_account_di partition (dw_etl_dt = '2020-12-02')
select
t2.user_name
, t2.balance
, t2.create_time
, t2.update_time
from (
select t1.user_name
, t1.balance
, t1.create_time
, t1.update_time
, row_number() over (partition by user_name order by update_time desc) rn
from (
select user_name
, balance
, create_time
, update_time
from lgdw_dwd.user_account_di
where dw_etl_dt = '2020-12-01'
union all
select user_name
, balance
, create_time
, update_time
from lgdw_ods.user_account_20201202
)t1
)t2
where t2.rn = 1 ;
拉链表
维护历史状态,以及最新状态数据
适用情况:
1.数据量比较大
2.表中的部分字段会被更新
3.需要查看某一个时间点或者时间段的历史快照信息
查看某一个订单在历史某一个时间点的状态
某一个用户在过去某一段时间,下单次数
4.更新的比例和频率不是很大
如果表中信息变化不是很大,每天都保留一份全量,那么每次全量中会保存很多不变的信息,对存储是极大的浪费
优点
1、满足反应数据的历史状态
2、最大程度节省存储
1201全量数据到ODS(同上,略)
建立dwd层拉链表
增加两个字段:
dw_start_dt(表示该条记录的生命周期开始时间——周期快照时的状态)
dw_end_dt(该条记录的生命周期结束时间)
dw_end_dt= ‘9999-12-31’ 表示该条记录目前处于有效状态
create table lgdw_dwd.user_account_dz(
user_name string COMMENT '用户名'
,balance string COMMENT '余额'
,create_time timestamp COMMENT '创建时间'
,update_time timestamp COMMENT '更新时间'
,dw_start_dt date COMMENT '开始生效日期'
,dw_end_dt date COMMENT '结束生效日期'
) COMMENT '账户余额表'
partitioned by (dw_etl_dt string)
row format delimited fields terminated by ','
;
注:第一次加工的时候需要初始化所有数据,dw_start_dt 设置为数据日期 2020-12-01,dw_end_dt设置为9999-12-31
insert overwrite table lgdw_dwd.user_account_dz partition(dw_etl_dt = '2020-12-01')
select
user_name
,balance
,create_time
,update_time
,to_date(update_time) as dw_start_dt
,'9999-12-31' as dw_end_dt
from
lgdw_ods.user_account_20201201
;
参考:
https://mp.weixin.qq.com/s/qAk4XGvTRdxZH7XbFQ70Mw
标签:数仓,account,12,快照,全量表,lgdw,user,time,2020 来源: https://blog.csdn.net/liuge36/article/details/110591159