数仓潮汐猎人 | 数据仓库企业数仓拉链表制作
拉链表
拉链表是针对数据仓库设计中表存储数据的方式而定义的,顾名思义,所谓拉链,就是记录历史。记录一个事物从开始,一直到当前状态的所有变化的信息。
下面就是一张拉链表,存储的是用户的最基本信息以及每条记录的生命周期。我们可以使用这张表拿到最新的当天的最新数据以及之前的历史数据。
说明:
t_start_date 表示该条记录的生命周期开始时间,t_end_date 表示该条记录的生命周期结束时间;
t_end_date = ‘9999-12-31’表示该条记录目前处于有效状态;
如果查询当前所有有效的记录,则select * from user where t_end_date = ‘9999-12-31′
如果查询2017-01-01的历史快照,则select * from user where t_start_date <= ‘2017-01-01′ and end_date >= ‘2017-01-01’,这条语句会查询到以下记录:
拉链表的使用场景
在数据仓库的数据模型设计过程中,经常会遇到下面这种表的设计:
1.有一些表的数据量很大,比如一张用户表,大约10亿条记录,50个字段,这种表,即使使用ORC压缩,单张表的存储也会超过100G,在HDFS使用双备份或者三备份的话就更大一些。
2.表中的部分字段会被update更新操作,如用户联系方式,产品的描述信息,订单的状态等等。
3.需要查看某一个时间点或者时间段的历史快照信息,比如,查看某一个订单在历史某一个时间点的状态。
4.表中的记录变化的比例和频率不是很大,比如,总共有10亿的用户,每天新增和发生变化的有200万左右,变化的比例占的很小。
对于这种表的设计?下面有几种方案可选:
方案一:每天只留最新的一份,比如我们每天用datax抽取最新的一份全量数据到Hive中。
方案二:每天保留一份全量的切片数据。
方案三:使用拉链表。
方案一:每天只留最新的一份
这种方案就不用多说了,实现起来很简单,每天drop掉前一天的数据,重新抽一份最新的。优点很明显,节省空间,一些普通的使用也很方便,不用在选择表的时候加一个时间分区什么的。缺点同样明显,没有历史数据,先翻翻旧账只能通过其它方式,比如从流水表里面抽。
方案二:每天保留一份全量的切片数据
每天一份全量的切片是一种比较稳妥的方案,而且历史数据也在。缺点就是存储空间占用量太大太大了,如果对这边表每天都保留一份全量,那么每次全量中会保存很多不变的信息,对存储是极大的浪费。当然我们也可以做一些取舍,比如只保留近一个月的数据?但是,需求是无耻的,数据的生命周期不是我们能完全左右的。
方案三:拉链表
拉链表在使用上基本兼顾了我们的需求。首先它在空间上做了一个取舍,虽说不像方案一那样占用量那么小,但是它每日的增量可能只有方案二的千分之一甚至是万分之一。其实它能满足方案二所能满足的需求,既能获取最新的数据,也能添加筛选条件也获取历史的数据。所以我们还是很有必要来使用拉链表的。
拉链表的设计
在Mysql关系型数据库里的user表中信息变化。
在2017-01-01表中的数据是:
在2017-01-02表中的数据是,用户002和004资料进行了修改,005是新增用户:
在2017-01-03表中的数据是,用户004和005资料进行了修改,006是新增用户:
如果在数据仓库中设计成历史拉链表保存该表,则会有下面这样一张表,这是最新一天(即2017-01-03)的数据:
说明:
t_start_date 表示该条记录的生命周期开始时间,t_end_date 表示该条记录的生命周期结束时间;
t_end_date = ‘9999-12-31’表示该条记录目前处于有效状态;
如果查询当前所有有效的记录,则select * from user where t_end_date = ‘9999-12-31′
如果查询2017-01-01的历史快照,则select * from user where t_start_date <= ‘2017-01-01′ and end_date >= ‘2017-01-01’,这条语句会查询到以下记录:
拉链表的实现与更新
Hive中实现拉链表
我们需要一张ODS层的用户全量表。至少需要用它来初始化。每日的用户更新表。而且我们要确定拉链表的时间粒度,比如说拉链表每天只取一个状态,也就是说如果一天有3个状态变更,我们只取最后一个状态,这种天粒度的表其实已经能解决大部分的问题了。
获取每日的用户增量
监听Mysql数据的变化,比如说用Canal,最后合并每日的变化,获取到最后的一个状态。
假设我们每天都会获得一份切片数据,我们可以通过取两天切片数据的不同来作为每日更新表,这种情况下我们可以对所有的字段先进行concat,再取md5,这样就ok了。
流水表,有每日的变更流水表。
表结构 ods层的user表
CREATE EXTERNAL TABLE ods.user (user_num STRING COMMENT '用户编号',mobile STRING COMMENT '手机号码',reg_date STRING COMMENT '注册日期'
COMMENT '用户资料表'
PARTITIONED BY (dt string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\n'
STORED AS ORC
LOCATION '/ods/user';
)
ods层的user_update表
CREATE EXTERNAL TABLE ods.user_update (user_num STRING COMMENT '用户编号',mobile STRING COMMENT '手机号码',reg_date STRING COMMENT '注册日期'
COMMENT '每日用户资料更新表'
PARTITIONED BY (dt string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\n'
STORED AS ORC
LOCATION '/ods/user_update';
)
拉链表
CREATE EXTERNAL TABLE dws.user_his (user_num STRING COMMENT '用户编号',mobile STRING COMMENT '手机号码',reg_date STRING COMMENT '用户编号',t_start_date ,t_end_date
COMMENT '用户资料拉链表'
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\n'
STORED AS ORC
LOCATION '/dws/user_his';
)
更新
假设已经初始化了2017-01-01的日期,然后需要更新2017-01-02那一天的数据
INSERT OVERWRITE TABLE dws.user_his
SELECT * FROM
(SELECT A.user_num,A.mobile,A.reg_date,A.t_start_time,CASEWHEN A.t_end_time = '9999-12-31' AND B.user_num IS NOT NULL THEN '2017-01-01'ELSE A.t_end_timeEND AS t_end_timeFROM dws.user_his AS ALEFT JOIN ods.user_update AS BON A.user_num = B.user_num
UNIONSELECT C.user_num,C.mobile,C.reg_date,'2017-01-02' AS t_start_time,'9999-12-31' AS t_end_timeFROM ods.user_update AS C
) AS T
补充
拉链表和流水表
流水表存放的是一个用户的变更记录,比如在一张流水表中,一天的数据中,会存放一个用户的每条修改记录,但是在拉链表中只有一条记录。这是拉链表设计时需要注意的一个粒度问题。我们当然也可以设置的粒度更小一些,一般按天就足够。
查询性能
链表当然也会遇到查询性能的问题,比如说我们存放了5年的拉链数据,那么这张表势必会比较大,当查询的时候性能就比较低了,个人认为两个思路来解决:
在一些查询引擎中,我们对start_date和end_date做索引,这样能提高不少性能。
保留部分历史数据,比如说我们一张表里面存放全量的拉链表数据,然后再对外暴露一张只提供近3个月数据的拉链表。
推荐阅读:
那些被问懵逼的数仓面试题
58基于Flink构建实时数仓实践
干货,OLAP数仓从百万到百亿级数据量实时分析
数仓潮汐猎人 | 数据仓库企业数仓拉链表制作相关推荐
- 数仓--拉链表(原理、设计以及在Hive中的实现)
拉链表 什么是拉链表? 谈到拉链表就不得不谈SCD(缓慢变化维问题) 缓慢变化维怎么解决?(粗看有五种) 保留初始值(不让改) 改写属性值 ==增加维度新行== 增加维度新列 使用历史表 举一个具体的 ...
- 用友BIP产品矩阵亮相首届中小企业数字化转型大会,数智创新驱动企业高效成长
11月9日-10日,由工业和信息化部.山东省人民政府联合主办的2022全国中小企业数字化转型大会在山东济南召开.本次大会以"创新引领发展 数字点亮未来"为主题,聚焦以数字化转型为路 ...
- 免费下载|《建设数字中国 升级数智底座-企业数智化底座白皮书》
企业数智化历经多年的演进,已经从最初的"局部推动业务提质增效",发展为"利用技术全面赋能业务创新活动",数智化能力的建设正逐步与企业的战略目标深度融合.企业践行 ...
- 畅享企业数智化 银弹谷亮相第六届工程建设行业互联网大会
日前,由中国施工企业管理协会主办的第六届中国工程建设行业互联网大会在苏州太湖国际会议中心圆满举行.本届大会以"数智建造赋能高质量发展"为主题,旨在深入贯彻国家经济发展战略,深入推进 ...
- 数据仓库数据模型之:极限存储--历史拉链表
摘要: 在数据仓库的数据模型设计过程中,经常会遇到文内所提到的这样的需求.而历史拉链表,既能满足对历史数据的需求,又能很大程度的节省存储资源. 在数据仓库的数据模型设计过程中,经常会遇到这样的需求: ...
- hive中实现行转列_漫谈数据仓库之拉链表(原理、设计以及在Hive中的实现)
全文由下面几个部分组成: 先分享一下拉链表的用途.什么是拉链表. 通过一些小的使用场景来对拉链表做近一步的阐释,以及拉链表和常用的切片表的区别. 举一个具体的应用场景,来设计并实现一份拉链表,最后并通 ...
- hive内部表和外部表的区别_HIVE拉链表实现
背景 https://www.cnblogs.com/lxbmaomao/p/9821128.htmlwww.cnblogs.com 拉链表是针对数据仓库设计中表存储数据的方式而定义的,主要是维护历 ...
- (35)用户维度表(拉链表)
用户表中的数据每日既有可能新增,也有可能修改,但修改频率并不高,属于缓慢变化 维度,此处采用拉链表存储用户维度数据. 1 )什么是拉链表 2)为什么要做拉链表 3)拉链表形成过程 4)拉链表制作过程图 ...
- 数据仓库(二) 数仓理论(重点核心)
文章目录 数据仓库(二) 数仓理论(重点核心) 数仓分层 数据仓库分层 ODS层 DWD层 DWS层 DWT层 ADS层 数据仓库分层的好处 关系建模与维度建模 关系建模 维度建模 星型模型 雪花模型 ...
最新文章
- bzoj2154 Crash的数字表格
- php 实现查询百度排名,PHP实现获取百度top50的搜索排行关键字
- vw实现移动端自适应页面
- 数据挖掘流程(三):特征工程
- LeetCode 93. 复原IP地址(回溯)
- 无国界医生_如何在5分钟内创建无国界风格的技能树
- mysql触发器的简单入门(二)
- js 怎么使一个absolute覆盖在父类上面_JS基础-完美掌握继承知识点
- tesseract 提升识别质量
- Python自动化(十二):一分钟搞定几百个Excel中查找的数据
- opencv转单通道python_在OpenCv(Python)中查找单通道图像的目录
- 吉米多维奇数学分析每日一题--习题1382
- 屏幕种类有哪些,特点,怎么挑?TFT、LCD、OLED、IPS、TN的含义与区别?高色域、刷新率、广视角、雾面屏又是什么?
- 53Java模拟器,515最好的java模拟器
- L1-009 N个数求和(解决测试点三错误)
- 第九章 姜小白大难不死登君位 公子纠迟来一步梦成空
- Dev-C++的使用(一):下载、安装与基本使用
- 银监会计算机专业考试,)(2015国家公务员考试银监会计算机专业考试分析
- 车用总线 | CAN XL最新技术的CiA官方解答
- 视频特效滤镜 via Media Foundation Transform (MFT)
热门文章
- 【自我陈述】描述自我现状,及日后的一些小规划。
- 西安工大计算机学院李颖,李颖-吉林大学计算机科学与技术学院
- 教你快速实现Nexus刷机
- 基于JAVAMVC土特产交易平台系统计算机毕业设计源码+数据库+lw文档+系统+部署
- linux常见命令与FileZilla
- 花朵授粉算法【记录】
- springcloud讲解
- 苹果6s系统升级无服务器,iPhone6s升级至iOS13,如果没换新电池,最好别更新
- 10.17面试类题1:V23双向数据绑定,2:defineProperty,3.sass和scss
- 一加6html查看程序,一加手机6亮相ChinaJoy,终于明白西装暴徒含义