数据仓库中历史拉链表的更新方法
原文地址:http://lxw1234.com/archives/2015/08/473.htm
这里简单介绍一下这种历史拉链表的更新方法。
本文中假设:
- 数据仓库中订单历史表的刷新频率为一天,当天更新前一天的增量数据;
- 如果一个订单在一天内有多次状态变化,则只会记录最后一个状态的历史;
- 订单状态包括三个:创建、支付、完成;
- 创建时间和修改时间只取到天,如果源订单表中没有状态修改时间,那么抽取增量就比较麻烦,需要有个机制来确保能抽取到每天的增量数据;
- 本文中的表和SQL都使用Hive的HQL语法;
- 源系统中订单表结构为:
CREATE TABLE orders (
orderid INT,
createtime STRING,
modifiedtime STRING,
status STRING
) stored AS textfile;
7.在数据仓库的ODS层,有一张订单的增量数据表,按天分区,存放每天的增量数据:
CREATE TABLE t_ods_orders_inc (
orderid INT,
createtime STRING,
modifiedtime STRING,
status STRING
) PARTITIONED BY (day STRING)
stored AS textfile;
8. 在数据仓库的DW层,有一张订单的历史数据拉链表,存放订单的历史状态数据:
CREATE TABLE t_dw_orders_his (
orderid INT,
createtime STRING,
modifiedtime STRING,
status STRING,
dw_start_date STRING,
dw_end_date STRING
) stored AS textfile;
9. 暂未考虑Hive上表的查询性能问题,只实现功能;
华丽的分割线:您可以关注 lxw的大数据田地 ,或者 加入邮件列表 ,随时接收博客更新的通知邮件。
10. 2015-08-21至2015-08-23,每天原系统订单表的数据如下,红色标出的为当天发生变化的订单,即增量数据:
全量初始化
在数据从源业务系统每天正常抽取和刷新到DW订单历史表之前,需要做一次全量的初始化,就是从源订单表中昨天以前的数据全部抽取到ODW,并刷新到DW。
以上面的数据为例,比如在2015-08-21这天做全量初始化,那么我需要将包括2015-08-20之前的所有的数据都抽取并刷新到DW:
第一步,抽取全量数据到ODS:
INSERT overwrite TABLE t_ods_orders_inc PARTITION (day = ‘2015-08-20′)
SELECT orderid,createtime,modifiedtime,status
FROM orders
WHERE createtime <= ‘2015-08-20′;
第二步,从ODS刷新到DW:
INSERT overwrite TABLE t_dw_orders_his
SELECT orderid,createtime,modifiedtime,status,
createtime AS dw_start_date,
‘9999-12-31′ AS dw_end_date
FROM t_ods_orders_inc
WHERE day = ‘2015-08-20′;
完成后,DW订单历史表中数据如下:
- spark-sql> select * from t_dw_orders_his;
- 1 2015-08-18 2015-08-18 创建 2015-08-18 9999-12-31
- 2 2015-08-18 2015-08-18 创建 2015-08-18 9999-12-31
- 3 2015-08-19 2015-08-21 支付 2015-08-19 9999-12-31
- 4 2015-08-19 2015-08-21 完成 2015-08-19 9999-12-31
- 5 2015-08-19 2015-08-20 支付 2015-08-19 9999-12-31
- 6 2015-08-20 2015-08-20 创建 2015-08-20 9999-12-31
- 7 2015-08-20 2015-08-21 支付 2015-08-20 9999-12-31
- Time taken: 2.296 seconds, Fetched 7 row(s)
华丽的分割线:您可以关注 lxw的大数据田地 ,或者 加入邮件列表 ,随时接收博客更新的通知邮件。
增量抽取
每天,从源系统订单表中,将前一天的增量数据抽取到ODS层的增量数据表。
这里的增量需要通过订单表中的创建时间和修改时间来确定:
INSERT overwrite TABLE t_ods_orders_inc PARTITION (day = ‘${day}‘)
SELECT orderid,createtime,modifiedtime,status
FROM orders
WHERE createtime = ‘${day}’ OR modifiedtime = ‘${day}';
注意:在ODS层按天分区的增量表,最好保留一段时间的数据,比如半年,为了防止某一天的数据有问题而回滚重做数据。
增量刷新历史数据
从2015-08-22开始,需要每天正常刷新前一天(2015-08-21)的增量数据到历史表。
第一步,通过增量抽取,将2015-08-21的数据抽取到ODS:
INSERT overwrite TABLE t_ods_orders_inc PARTITION (day = ‘2015-08-21′)
SELECT orderid,createtime,modifiedtime,status
FROM orders
WHERE createtime = ‘2015-08-21′ OR modifiedtime = ‘2015-08-21′;
ODS增量表中2015-08-21的数据如下:
- spark-sql> select * from t_ods_orders_inc where day = '2015-08-21';
- 3 2015-08-19 2015-08-21 支付 2015-08-21
- 4 2015-08-19 2015-08-21 完成 2015-08-21
- 7 2015-08-20 2015-08-21 支付 2015-08-21
- 8 2015-08-21 2015-08-21 创建 2015-08-21
- Time taken: 0.437 seconds, Fetched 4 row(s)
第二步,通过DW历史数据(数据日期为2015-08-20),和ODS增量数据(2015-08-21),刷新历史表:
先把数据放到一张临时表中:
- DROP TABLE IF EXISTS t_dw_orders_his_tmp;
- CREATE TABLE t_dw_orders_his_tmp AS
- SELECT orderid,
- createtime,
- modifiedtime,
- status,
- dw_start_date,
- dw_end_date
- FROM (
- SELECT a.orderid,
- a.createtime,
- a.modifiedtime,
- a.status,
- a.dw_start_date,
- CASE WHEN b.orderid IS NOT NULL AND a.dw_end_date > '2015-08-21' THEN '2015-08-20' ELSE a.dw_end_date END AS dw_end_date
- FROM t_dw_orders_his a
- left outer join (SELECT * FROM t_ods_orders_inc WHERE day = '2015-08-21') b
- ON (a.orderid = b.orderid)
- UNION ALL
- SELECT orderid,
- createtime,
- modifiedtime,
- status,
- modifiedtime AS dw_start_date,
- '9999-12-31' AS dw_end_date
- FROM t_ods_orders_inc
- WHERE day = '2015-08-21'
- ) x
- ORDER BY orderid,dw_start_date;
其中:
UNION ALL的两个结果集中,第一个是用历史表left outer join 日期为 ${yyy-MM-dd} 的增量,能关联上的,并且dw_end_date > ${yyy-MM-dd},说明状态有变化,则把原来的dw_end_date置为(${yyy-MM-dd} – 1), 关联不上的,说明状态无变化,dw_end_date无变化。
第二个结果集是直接将增量数据插入历史表。
最后把临时表中数据插入历史表:
INSERT overwrite TABLE t_dw_orders_his
SELECT * FROM t_dw_orders_his_tmp;
华丽的分割线:您可以关注 lxw的大数据田地 ,或者 加入邮件列表 ,随时接收博客更新的通知邮件。
刷新完后,历史表中数据如下:
- spark-sql> select * from t_dw_orders_his order by orderid,dw_start_date;
- 1 2015-08-18 2015-08-18 创建 2015-08-18 9999-12-31
- 2 2015-08-18 2015-08-18 创建 2015-08-18 9999-12-31
- 3 2015-08-19 2015-08-21 支付 2015-08-19 2015-08-20
- 3 2015-08-19 2015-08-21 支付 2015-08-21 9999-12-31
- 4 2015-08-19 2015-08-21 完成 2015-08-19 2015-08-20
- 4 2015-08-19 2015-08-21 完成 2015-08-21 9999-12-31
- 5 2015-08-19 2015-08-20 支付 2015-08-19 9999-12-31
- 6 2015-08-20 2015-08-20 创建 2015-08-20 9999-12-31
- 7 2015-08-20 2015-08-21 支付 2015-08-20 2015-08-20
- 7 2015-08-20 2015-08-21 支付 2015-08-21 9999-12-31
- 8 2015-08-21 2015-08-21 创建 2015-08-21 9999-12-31
- Time taken: 0.717 seconds, Fetched 11 row(s)
由于在2015-08-21做了8月20日以前的数据全量初始化,而订单3、4、7在2015-08-21的增量数据中也存在,因此都有两条记录,但不影响后面的查询。
再看将2015-08-22的增量数据刷新到历史表:
- INSERT overwrite TABLE t_ods_orders_inc PARTITION (day = '2015-08-22')
- SELECT orderid,createtime,modifiedtime,status
- FROM orders
- WHERE createtime = '2015-08-22' OR modifiedtime = '2015-08-22';
- DROP TABLE IF EXISTS t_dw_orders_his_tmp;
- CREATE TABLE t_dw_orders_his_tmp AS
- SELECT orderid,
- createtime,
- modifiedtime,
- status,
- dw_start_date,
- dw_end_date
- FROM (
- SELECT a.orderid,
- a.createtime,
- a.modifiedtime,
- a.status,
- a.dw_start_date,
- CASE WHEN b.orderid IS NOT NULL AND a.dw_end_date > '2015-08-22' THEN '2015-08-21' ELSE a.dw_end_date END AS dw_end_date
- FROM t_dw_orders_his a
- left outer join (SELECT * FROM t_ods_orders_inc WHERE day = '2015-08-22') b
- ON (a.orderid = b.orderid)
- UNION ALL
- SELECT orderid,
- createtime,
- modifiedtime,
- status,
- modifiedtime AS dw_start_date,
- '9999-12-31' AS dw_end_date
- FROM t_ods_orders_inc
- WHERE day = '2015-08-22'
- ) x
- ORDER BY orderid,dw_start_date;
- INSERT overwrite TABLE t_dw_orders_his
- SELECT * FROM t_dw_orders_his_tmp;
刷新完后历史表数据如下:
- spark-sql> select * from t_dw_orders_his order by orderid,dw_start_date;
- 1 2015-08-18 2015-08-18 创建 2015-08-18 2015-08-21
- 1 2015-08-18 2015-08-22 支付 2015-08-22 9999-12-31
- 2 2015-08-18 2015-08-18 创建 2015-08-18 2015-08-21
- 2 2015-08-18 2015-08-22 完成 2015-08-22 9999-12-31
- 3 2015-08-19 2015-08-21 支付 2015-08-19 2015-08-20
- 3 2015-08-19 2015-08-21 支付 2015-08-21 9999-12-31
- 4 2015-08-19 2015-08-21 完成 2015-08-19 2015-08-20
- 4 2015-08-19 2015-08-21 完成 2015-08-21 9999-12-31
- 5 2015-08-19 2015-08-20 支付 2015-08-19 9999-12-31
- 6 2015-08-20 2015-08-20 创建 2015-08-20 2015-08-21
- 6 2015-08-20 2015-08-22 支付 2015-08-22 9999-12-31
- 7 2015-08-20 2015-08-21 支付 2015-08-20 2015-08-20
- 7 2015-08-20 2015-08-21 支付 2015-08-21 9999-12-31
- 8 2015-08-21 2015-08-21 创建 2015-08-21 2015-08-21
- 8 2015-08-21 2015-08-22 支付 2015-08-22 9999-12-31
- 9 2015-08-22 2015-08-22 创建 2015-08-22 9999-12-31
- 10 2015-08-22 2015-08-22 支付 2015-08-22 9999-12-31
- Time taken: 0.66 seconds, Fetched 17 row(s)
华丽的分割线:您可以关注 lxw的大数据田地 ,或者 加入邮件列表 ,随时接收博客更新的通知邮件。
查看2015-08-21的历史快照数据:
- spark-sql> select * from t_dw_orders_his where dw_start_date <= '2015-08-21' and dw_end_date >= '2015-08-21';
- 1 2015-08-18 2015-08-18 创建 2015-08-18 2015-08-21
- 2 2015-08-18 2015-08-18 创建 2015-08-18 2015-08-21
- 3 2015-08-19 2015-08-21 支付 2015-08-21 9999-12-31
- 4 2015-08-19 2015-08-21 完成 2015-08-21 9999-12-31
- 5 2015-08-19 2015-08-20 支付 2015-08-19 9999-12-31
- 6 2015-08-20 2015-08-20 创建 2015-08-20 2015-08-21
- 7 2015-08-20 2015-08-21 支付 2015-08-21 9999-12-31
- 8 2015-08-21 2015-08-21 创建 2015-08-21 2015-08-21
订单1在2015-08-21的时候还处于创建的状态,在2015-08-22的时候状态变为支付。
再刷新2015-08-23的增量数据:
按照上面的方法刷新完后,历史表数据如下:
- spark-sql> select * from t_dw_orders_his order by orderid,dw_start_date;
- 1 2015-08-18 2015-08-18 创建 2015-08-18 2015-08-21
- 1 2015-08-18 2015-08-22 支付 2015-08-22 2015-08-22
- 1 2015-08-18 2015-08-23 完成 2015-08-23 9999-12-31
- 2 2015-08-18 2015-08-18 创建 2015-08-18 2015-08-21
- 2 2015-08-18 2015-08-22 完成 2015-08-22 9999-12-31
- 3 2015-08-19 2015-08-21 支付 2015-08-19 2015-08-20
- 3 2015-08-19 2015-08-21 支付 2015-08-21 2015-08-22
- 3 2015-08-19 2015-08-23 完成 2015-08-23 9999-12-31
- 4 2015-08-19 2015-08-21 完成 2015-08-19 2015-08-20
- 4 2015-08-19 2015-08-21 完成 2015-08-21 9999-12-31
- 5 2015-08-19 2015-08-20 支付 2015-08-19 2015-08-22
- 5 2015-08-19 2015-08-23 完成 2015-08-23 9999-12-31
- 6 2015-08-20 2015-08-20 创建 2015-08-20 2015-08-21
- 6 2015-08-20 2015-08-22 支付 2015-08-22 9999-12-31
- 7 2015-08-20 2015-08-21 支付 2015-08-20 2015-08-20
- 7 2015-08-20 2015-08-21 支付 2015-08-21 9999-12-31
- 8 2015-08-21 2015-08-21 创建 2015-08-21 2015-08-21
- 8 2015-08-21 2015-08-22 支付 2015-08-22 2015-08-22
- 8 2015-08-21 2015-08-23 完成 2015-08-23 9999-12-31
- 9 2015-08-22 2015-08-22 创建 2015-08-22 9999-12-31
- 10 2015-08-22 2015-08-22 支付 2015-08-22 9999-12-31
- 11 2015-08-23 2015-08-23 创建 2015-08-23 9999-12-31
- 12 2015-08-23 2015-08-23 创建 2015-08-23 9999-12-31
- 13 2015-08-23 2015-08-23 支付 2015-08-23 9999-12-31
订单1从20号-23号,状态变化了三次,历史表中有三条记录。
- //查看2015-08-22当天的历史快照,可以看出,和上面图中2015-08-22时候订单表中的数据是一样的
- spark-sql> select * from t_dw_orders_his where dw_start_date <= '2015-08-22' and dw_end_date >= '2015-08-22';
- 1 2015-08-18 2015-08-22 支付 2015-08-22 2015-08-22
- 2 2015-08-18 2015-08-22 完成 2015-08-22 9999-12-31
- 3 2015-08-19 2015-08-21 支付 2015-08-21 2015-08-22
- 4 2015-08-19 2015-08-21 完成 2015-08-21 9999-12-31
- 5 2015-08-19 2015-08-20 支付 2015-08-19 2015-08-22
- 6 2015-08-20 2015-08-22 支付 2015-08-22 9999-12-31
- 7 2015-08-20 2015-08-21 支付 2015-08-21 9999-12-31
- 8 2015-08-21 2015-08-22 支付 2015-08-22 2015-08-22
- 9 2015-08-22 2015-08-22 创建 2015-08-22 9999-12-31
- 10 2015-08-22 2015-08-22 支付 2015-08-22 9999-12-31
- Time taken: 0.328 seconds, Fetched 10 row(s)
- //查看当前所有订单的最新状态
- spark-sql> select * from t_dw_orders_his where dw_end_date = '9999-12-31';
- 1 2015-08-18 2015-08-23 完成 2015-08-23 9999-12-31
- 2 2015-08-18 2015-08-22 完成 2015-08-22 9999-12-31
- 3 2015-08-19 2015-08-23 完成 2015-08-23 9999-12-31
- 4 2015-08-19 2015-08-21 完成 2015-08-21 9999-12-31
- 5 2015-08-19 2015-08-23 完成 2015-08-23 9999-12-31
- 6 2015-08-20 2015-08-22 支付 2015-08-22 9999-12-31
- 7 2015-08-20 2015-08-21 支付 2015-08-21 9999-12-31
- 8 2015-08-21 2015-08-23 完成 2015-08-23 9999-12-31
- 9 2015-08-22 2015-08-22 创建 2015-08-22 9999-12-31
- 10 2015-08-22 2015-08-22 支付 2015-08-22 9999-12-31
- 11 2015-08-23 2015-08-23 创建 2015-08-23 9999-12-31
- 12 2015-08-23 2015-08-23 创建 2015-08-23 9999-12-31
- 13 2015-08-23 2015-08-23 支付 2015-08-23 9999-12-31
- Time taken: 0.293 seconds, Fetched 13 row(s)
转载请注明:lxw的大数据田地 » 数据仓库中历史拉链表的更新方法
数据仓库中历史拉链表的更新方法相关推荐
- Hive数据仓库中历史拉链表实践
数据准备 在mysql中创建测试表orders CREATE TABLE `orders` (`orderid` int(11) NOT NULL AUTO_INCREMENT,`status` va ...
- 【clickhouse】数据仓库中的拉链表(Clickhouse 实现)
文章目录 1.概述 在 Clickhouse 中实现拉链表 一. 每日的用户更新表: 二. ods 层的 user 表: ods 层的 user_update 表 拉链表: 拉链表和流水表: 查询性能 ...
- 数据仓库数据模型之:极限存储--历史拉链表
摘要: 在数据仓库的数据模型设计过程中,经常会遇到文内所提到的这样的需求.而历史拉链表,既能满足对历史数据的需求,又能很大程度的节省存储资源. 在数据仓库的数据模型设计过程中,经常会遇到这样的需求: ...
- hive 分区_Hive下数据仓库历史拉链表如何加工,分区键该如何选择
缓慢变化维 说到历史拉链表,首先得说下缓慢变化维. 在现实世界中,维度的属性并不是静态的,而是随着时间的变化而变化,这也体现了数据仓库的特点之一,是反映历史变化的.相对于数据增长较为快速的事实表,维度 ...
- greenplum 历史拉链表
3.1 历史拉链表 数据仓库定义:是一个面向主题的.集成的.相对稳定的.反映历史变化的数据集合,用于支持管理决策. 历史拉链表:一种数据模型,主要是针对数据仓库设计中表存储数据的方式而定义的.它记录了 ...
- 数据仓库历史数据存储-拉链表
拉链表 拉链表是维护历史状态.以及最新状态的一种方式. 拉链表对快照表进行了优化,根据拉链粒度(一般为时间)的不同,去除了在粒度范围内不变的数据. 拉链表可以维护两个时间(start_time, en ...
- hql取满足条件最新一条记录_数据仓库怎么做拉链表记录数据变化情况,看看这篇文章 就明白了...
小文老师给你讲解数据仓库的ETL拉链算法,通过这篇文档,让你快速了解数据拉链. 一 首先我们先来看下,什么是拉链?在数据仓库中,拉链就是记录数据在某一时间区间内的状态以及数据在某一时间点上的数据变化的 ...
- 数据仓库历史数据存储 - 拉链表
假如我们有一个账号account表,我们需要在hive中存储(数据是从线上mysql读取binlog同步来的,是有明细变化的) account表结构:account_id, username, fol ...
- word中参考文献编号添加及更新方法
写论文离不开引用 引用小技巧这里做下笔记: 方法如下: 我们首先对参考文献进行编号,编号的详细过程如图中所示: 将光标置于文中引用位置,点击插入->交叉引用 选择相应文献,插入 参考文献中有变动 ...
最新文章
- MQTT在Windows下搭建MQTT服务器
- python基础语法 第0关print-徐州鼓楼高校邦数据科学通识课【Python基础语法】答案...
- layui根据name获取对象_JavaScript对象 - 初识
- JavaScript中eval()函数
- 奥拉星插件flash下载手机版下载安装_奥拉星游戏插件
- 前魅族李楠创办“怒喵科技”,网友:看半天不知道公司干嘛的
- Spring mvc 异常处理
- Python基础----日期时间
- 酒店后台管理系统、客栈管理、入住会员、房间管理、房源、房型、订单、报表、酒店企业、短信模板、积分、打印、交接班、住宿、入住、锁房、收支流水、房间销售、消费项目、酒店管理、渠道销售、支付管理、连锁酒店
- 【pytest之allure测试报告使用】
- Java创建Excel文档(自定义格式)
- 百度网盘提取码_利用审查元素自定义百度网盘提取码教程 无需工具
- 机组组合问题常用术语
- 51单片机PWM调速风扇转速显示转速设置
- 微信小程序云开发联表查询【聚合】
- 新手小白大学生,在宿舍做短视频自媒体,两个星期收益1700多
- oracle中 ''dual'' 的含义
- wps分析工具库如何加载_【数据分析】关键词数据分析如何做?用这个工具比指数好...
- PS(2018)更换启动界面
- 华师计算机学院教师资格证,教师资格认证
热门文章
- DevOps 工程师需要必备哪些技能?
- Go语言类库-reflect(反射)
- java.lang.NoClassDefFoundError: javax/servlet/http/HttpServlet
- 游戏开发程序员可能会遇到的英文单词
- tp中ueditor编辑器的使用
- 阿里云邮箱域名解析设置要求
- 语言认知模型--的学习笔记
- 修复Critical dependency: the request of a dependency is an expression警告
- JS:变量提升与临时性死区TDZ
- python的round函数使用