大数据平台数仓数湖hive之拉链表高效实现

对于缓慢变化的维度表,如客户表,员工表,为了不丢失历史数据,又不至于太浪费存储空间,我们采用拉链表实现。
实现过程如下:

1、采集初始数据:

1.1 从mysql导出数据到hdfs

/data/dolphinscheduler/loadMysqlTable.sh "${dbConnect}" "select ${slctColums} from loan.${tableName} t where update_time < date_add('${bizDate}', INTERVAL 1 DAY) or update_time is null" "/dmp/${DMP_DB}" "${srcSystem}" "${bizDate}"

关于loadMysqlTable.sh脚本可以看我的另一篇文章:
https://blog.csdn.net/weixin_45357522/article/details/149720803
其中,变量的示例:
${slctColums}:“t.id, t.name, t.age …”
${dbConnect}:“-h host1 -uroot -ppwd123”
${tableName}: “t_customer”
${bizDate}: “2025-07-30”
${srcSystem}: “crm”
${DMP_DB}: 数据中台的hive db name, 如:“rdm”

这里要注意的是sql语句加入一个条件,update_time < date_add(‘${bizDate}’, INTERVAL 1 DAY) or update_time is null,只把T-1以前更新的数据导出来,当时更新的数据要等到第二天才导出,以免重复导入,产生假的变更记录。

1.2 基于上传到hdfs的文件创建一个临时表

1.3 从临时表中过滤掉非法数据,如id为空的数据,加载到ODS

1.4 从ods表加载到dwd,并初始化valid_from = ‘1900-01-01’, valid_to = ‘2999-12-31’

insert overwrite table ${DMP_DB}.dwd_dim_${tableName}
SELECT ${slctColums}, '1900-01-01', '2999-12-31'
from ${DMP_DB}.ods_${srcSystem}_${tableName} t;

其中,${slctColums}的示例:t.id, t.name, t.age …
dwd表最后两个字段分别是valid_from, valid_to, 日期型
表结构示例:

CREATE TABLE cust.dwd_dim_loan_individual_customer (
  id varchar(32) COMMENT '个人客户id',
  code varchar(50) COMMENT '客户编号',
  name varchar(100) COMMENT '客户名称',
  status tinyint COMMENT '客户状态',
  id_type int COMMENT '证件类型 id_type',
  id_code varchar(22) COMMENT '证件号码',
  id_expire_date timestamp COMMENT '身份证有效期到',
  gender tinyint COMMENT '性别',
  age TINYINT COMMENT '年龄',
  valid_from date COMMENT '生效日期(含)',
  valid_to date COMMENT '失效日期(不含)'
)  COMMENT '个人客户'
STORED AS parquet 
location '/dmp/cust/dwd/dim/loan_individual_customer';

取数逻辑:

select ... from table1 
where valid_from <= current_date and current_date < valid_to

2、增量数据加载

2.1 从mysql导出数据到hdfs

/data/dolphinscheduler/loadMysqlTable.sh "${dbConnect}" "select ${slctColums} from loan.${tableName} t where update_time < date_add('${bizDate}', INTERVAL 1 DAY) and update_time >= '${bizDate}'" "/dmp/${DMP_DB}" "${srcSystem}" "${bizDate}"

其中,只取更新时间是T-1的数据,T日更新数据留到下一天处理。

2.2 基于上传到hdfs的文件创建一个临时表

2.3 从临时表中过滤掉非法数据,如id为空的数据,加载到ODS

2.4 从ods表加载到dwd

这步比较关键,有些逻辑:

insert overwrite table ${DMP_DB}.dwd_dim_${tableName}
SELECT ${slctColums}, valid_from,
CASE 
  WHEN t.valid_to = to_date('2999-12-31') AND B.id IS NOT NULL
    THEN date_add('${bizDate}', 1)  -- 有新记录匹配到了,把valid_to设置为下一天
    ELSE t.valid_to  -- 没有新记录匹配到,valid_to不变
  END AS valid_to
FROM cust.dwd_dim_loan_individual_customer t
LEFT JOIN cust.ods_yecai_loan_individual_customer AS b
ON t.id = b.id 
 where valid_from != date_add('${bizDate}', 1) -- 重跑这个条件用于滤除当天先前加入的数据
UNION all -- 把新记录加进去
SELECT ${slctColums},date_add('${bizDate}', 1) AS valid_from, to_date('2999-12-31') AS valid_to
FROM ${DMP_DB}.ods_${srcSystem}_${tableName} AS t

重要优化就是旧表和新表只join一次!!!

示例数据:
a. 老数据

idnameagevalid_fromvalid_to
1张三251900-01-012999-12-31
2李四451900-01-012999-12-31

b.新数据

idnameage
1张三26

c. 合并后的数据

idnameagevalid_fromvalid_to
1张三251900-01-012025-07-31
1张三262025-07-312999-12-31
2李四451900-01-012999-12-31

sql中“where valid_from != date_add(‘${bizDate}’, 1)”的作用是在重跑数据时把当天新加入的数据滤除掉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值