热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

数仓潮汐猎人|数据仓库企业数仓拉链表制作​

拉链表拉链表是针对数据仓库设计中表存储数据的方式而定义的,顾名思义,所谓拉链,就是记录历史。记录一个事物从开始,一直到当前状

拉链表

拉链表是针对数据仓库设计中表存储数据的方式而定义的,顾名思义,所谓拉链,就是记录历史。记录一个事物从开始,一直到当前状态的所有变化的信息。

下面就是一张拉链表,存储的是用户的最基本信息以及每条记录的生命周期。我们可以使用这张表拿到最新的当天的最新数据以及之前的历史数据。

说明:

  • 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的历史快照&#xff0c;则select * from user where t_start_date <&#61; ‘2017-01-01′ and end_date >&#61; ‘2017-01-01’&#xff0c;这条语句会查询到以下记录&#xff1a;

拉链表的使用场景

在数据仓库的数据模型设计过程中&#xff0c;经常会遇到下面这种表的设计&#xff1a;

1.有一些表的数据量很大&#xff0c;比如一张用户表&#xff0c;大约10亿条记录&#xff0c;50个字段&#xff0c;这种表&#xff0c;即使使用ORC压缩&#xff0c;单张表的存储也会超过100G&#xff0c;在HDFS使用双备份或者三备份的话就更大一些。

2.表中的部分字段会被update更新操作&#xff0c;如用户联系方式&#xff0c;产品的描述信息&#xff0c;订单的状态等等。

3.需要查看某一个时间点或者时间段的历史快照信息&#xff0c;比如&#xff0c;查看某一个订单在历史某一个时间点的状态。

4.表中的记录变化的比例和频率不是很大&#xff0c;比如&#xff0c;总共有10亿的用户&#xff0c;每天新增和发生变化的有200万左右&#xff0c;变化的比例占的很小。

对于这种表的设计&#xff1f;下面有几种方案可选&#xff1a;

  • 方案一&#xff1a;每天只留最新的一份&#xff0c;比如我们每天用datax抽取最新的一份全量数据到Hive中。

  • 方案二&#xff1a;每天保留一份全量的切片数据。

  • 方案三&#xff1a;使用拉链表。

方案一&#xff1a;每天只留最新的一份

这种方案就不用多说了&#xff0c;实现起来很简单&#xff0c;每天drop掉前一天的数据&#xff0c;重新抽一份最新的。优点很明显&#xff0c;节省空间&#xff0c;一些普通的使用也很方便&#xff0c;不用在选择表的时候加一个时间分区什么的。缺点同样明显&#xff0c;没有历史数据&#xff0c;先翻翻旧账只能通过其它方式&#xff0c;比如从流水表里面抽。

方案二&#xff1a;每天保留一份全量的切片数据

每天一份全量的切片是一种比较稳妥的方案&#xff0c;而且历史数据也在。缺点就是存储空间占用量太大太大了&#xff0c;如果对这边表每天都保留一份全量&#xff0c;那么每次全量中会保存很多不变的信息&#xff0c;对存储是极大的浪费。当然我们也可以做一些取舍&#xff0c;比如只保留近一个月的数据&#xff1f;但是&#xff0c;需求是无耻的&#xff0c;数据的生命周期不是我们能完全左右的。

方案三&#xff1a;拉链表

拉链表在使用上基本兼顾了我们的需求。首先它在空间上做了一个取舍&#xff0c;虽说不像方案一那样占用量那么小&#xff0c;但是它每日的增量可能只有方案二的千分之一甚至是万分之一。其实它能满足方案二所能满足的需求&#xff0c;既能获取最新的数据&#xff0c;也能添加筛选条件也获取历史的数据。所以我们还是很有必要来使用拉链表的。

拉链表的设计

在Mysql关系型数据库里的user表中信息变化。

在2017-01-01表中的数据是&#xff1a;

在2017-01-02表中的数据是&#xff0c;用户002和004资料进行了修改&#xff0c;005是新增用户:

在2017-01-03表中的数据是&#xff0c;用户004和005资料进行了修改&#xff0c;006是新增用户:

如果在数据仓库中设计成历史拉链表保存该表&#xff0c;则会有下面这样一张表&#xff0c;这是最新一天&#xff08;即2017-01-03&#xff09;的数据&#xff1a;

说明&#xff1a;

  • t_start_date 表示该条记录的生命周期开始时间&#xff0c;t_end_date 表示该条记录的生命周期结束时间&#xff1b;

  • t_end_date &#61; ‘9999-12-31’表示该条记录目前处于有效状态&#xff1b;

  • 如果查询当前所有有效的记录&#xff0c;则select * from user where t_end_date &#61; ‘9999-12-31′

  • 如果查询2017-01-01的历史快照&#xff0c;则select * from user where t_start_date <&#61; ‘2017-01-01′ and end_date >&#61; ‘2017-01-01’&#xff0c;这条语句会查询到以下记录&#xff1a;

拉链表的实现与更新

Hive中实现拉链表

我们需要一张ODS层的用户全量表。至少需要用它来初始化。每日的用户更新表。而且我们要确定拉链表的时间粒度&#xff0c;比如说拉链表每天只取一个状态&#xff0c;也就是说如果一天有3个状态变更&#xff0c;我们只取最后一个状态&#xff0c;这种天粒度的表其实已经能解决大部分的问题了。

获取每日的用户增量
  1. 监听Mysql数据的变化&#xff0c;比如说用Canal&#xff0c;最后合并每日的变化&#xff0c;获取到最后的一个状态。

  2. 假设我们每天都会获得一份切片数据&#xff0c;我们可以通过取两天切片数据的不同来作为每日更新表&#xff0c;这种情况下我们可以对所有的字段先进行concat&#xff0c;再取md5&#xff0c;这样就ok了。

  3. 流水表&#xff0c;有每日的变更流水表。

表结构 ods层的user表

CREATE EXTERNAL TABLE ods.user (user_num STRING COMMENT &#39;用户编号&#39;,mobile STRING COMMENT &#39;手机号码&#39;,reg_date STRING COMMENT &#39;注册日期&#39;
COMMENT &#39;用户资料表&#39;
PARTITIONED BY (dt string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY &#39;\t&#39; LINES TERMINATED BY &#39;\n&#39;
STORED AS ORC
LOCATION &#39;/ods/user&#39;;
)

ods层的user_update表

CREATE EXTERNAL TABLE ods.user_update (user_num STRING COMMENT &#39;用户编号&#39;,mobile STRING COMMENT &#39;手机号码&#39;,reg_date STRING COMMENT &#39;注册日期&#39;
COMMENT &#39;每日用户资料更新表&#39;
PARTITIONED BY (dt string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY &#39;\t&#39; LINES TERMINATED BY &#39;\n&#39;
STORED AS ORC
LOCATION &#39;/ods/user_update&#39;;
)

拉链表

CREATE EXTERNAL TABLE dws.user_his (user_num STRING COMMENT &#39;用户编号&#39;,mobile STRING COMMENT &#39;手机号码&#39;,reg_date STRING COMMENT &#39;用户编号&#39;,t_start_date ,t_end_date
COMMENT &#39;用户资料拉链表&#39;
ROW FORMAT DELIMITED FIELDS TERMINATED BY &#39;\t&#39; LINES TERMINATED BY &#39;\n&#39;
STORED AS ORC
LOCATION &#39;/dws/user_his&#39;;
)

更新

假设已经初始化了2017-01-01的日期&#xff0c;然后需要更新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 &#61; &#39;9999-12-31&#39; AND B.user_num IS NOT NULL THEN &#39;2017-01-01&#39;ELSE A.t_end_timeEND AS t_end_timeFROM dws.user_his AS ALEFT JOIN ods.user_update AS BON A.user_num &#61; B.user_num
UNIONSELECT C.user_num,C.mobile,C.reg_date,&#39;2017-01-02&#39; AS t_start_time,&#39;9999-12-31&#39; AS t_end_timeFROM ods.user_update AS C
) AS T

补充

拉链表和流水表

流水表存放的是一个用户的变更记录&#xff0c;比如在一张流水表中&#xff0c;一天的数据中&#xff0c;会存放一个用户的每条修改记录&#xff0c;但是在拉链表中只有一条记录。这是拉链表设计时需要注意的一个粒度问题。我们当然也可以设置的粒度更小一些&#xff0c;一般按天就足够。

查询性能

链表当然也会遇到查询性能的问题&#xff0c;比如说我们存放了5年的拉链数据&#xff0c;那么这张表势必会比较大&#xff0c;当查询的时候性能就比较低了&#xff0c;个人认为两个思路来解决&#xff1a;

  1. 在一些查询引擎中&#xff0c;我们对start_date和end_date做索引&#xff0c;这样能提高不少性能。

  2. 保留部分历史数据&#xff0c;比如说我们一张表里面存放全量的拉链表数据&#xff0c;然后再对外暴露一张只提供近3个月数据的拉链表。

推荐阅读&#xff1a;

那些被问懵逼的数仓面试题

58基于Flink构建实时数仓实践

干货&#xff0c;OLAP数仓从百万到百亿级数据量实时分析


推荐阅读
  • 您的数据库配置是否安全?DBSAT工具助您一臂之力!
    本文探讨了Oracle提供的免费工具DBSAT,该工具能够有效协助用户检测和优化数据库配置的安全性。通过全面的分析和报告,DBSAT帮助用户识别潜在的安全漏洞,并提供针对性的改进建议,确保数据库系统的稳定性和安全性。 ... [详细]
  • 本文详细介绍了 Spark 中的弹性分布式数据集(RDD)及其常见的操作方法,包括 union、intersection、cartesian、subtract、join、cogroup 等转换操作,以及 count、collect、reduce、take、foreach、first、saveAsTextFile 等行动操作。 ... [详细]
  • HTTP(HyperTextTransferProtocol)是超文本传输协议的缩写,它用于传送www方式的数据。HTTP协议采用了请求响应模型。客服端向服务器发送一 ... [详细]
  • SQL 连接详解与应用
    本文详细介绍了 SQL 连接的概念、分类及实际应用,包括内连接、外连接、自连接等,并提供了丰富的示例代码。 ... [详细]
  • 本文介绍了如何使用Flume从Linux文件系统收集日志并存储到HDFS,然后通过MapReduce清洗数据,使用Hive进行数据分析,并最终通过Sqoop将结果导出到MySQL数据库。 ... [详细]
  • DAO(Data Access Object)模式是一种用于抽象和封装所有对数据库或其他持久化机制访问的方法,它通过提供一个统一的接口来隐藏底层数据访问的复杂性。 ... [详细]
  • 从0到1搭建大数据平台
    从0到1搭建大数据平台 ... [详细]
  • 本文总结了在SQL Server数据库中编写和优化存储过程的经验和技巧,旨在帮助数据库开发人员提升存储过程的性能和可维护性。 ... [详细]
  • 在 Ubuntu 中遇到 Samba 服务器故障时,尝试卸载并重新安装 Samba 发现配置文件未重新生成。本文介绍了解决该问题的方法。 ... [详细]
  • 本文详细介绍了MySQL数据库的基础语法与核心操作,涵盖从基础概念到具体应用的多个方面。首先,文章从基础知识入手,逐步深入到创建和修改数据表的操作。接着,详细讲解了如何进行数据的插入、更新与删除。在查询部分,不仅介绍了DISTINCT和LIMIT的使用方法,还探讨了排序、过滤和通配符的应用。此外,文章还涵盖了计算字段以及多种函数的使用,包括文本处理、日期和时间处理及数值处理等。通过这些内容,读者可以全面掌握MySQL数据库的核心操作技巧。 ... [详细]
  • 在《Cocos2d-x学习笔记:基础概念解析与内存管理机制深入探讨》中,详细介绍了Cocos2d-x的基础概念,并深入分析了其内存管理机制。特别是针对Boost库引入的智能指针管理方法进行了详细的讲解,例如在处理鱼的运动过程中,可以通过编写自定义函数来动态计算角度变化,利用CallFunc回调机制实现高效的游戏逻辑控制。此外,文章还探讨了如何通过智能指针优化资源管理和避免内存泄漏,为开发者提供了实用的编程技巧和最佳实践。 ... [详细]
  • 在使用 Cacti 进行监控时,发现已运行的转码机未产生流量,导致 Cacti 监控界面显示该转码机处于宕机状态。进一步检查 Cacti 日志,发现数据库中存在 SQL 查询失败的问题,错误代码为 145。此问题可能是由于数据库表损坏或索引失效所致,建议对相关表进行修复操作以恢复监控功能。 ... [详细]
  • 如何将TS文件转换为M3U8直播流:HLS与M3U8格式详解
    在视频传输领域,MP4虽然常见,但在直播场景中直接使用MP4格式存在诸多问题。例如,MP4文件的头部信息(如ftyp、moov)较大,导致初始加载时间较长,影响用户体验。相比之下,HLS(HTTP Live Streaming)协议及其M3U8格式更具优势。HLS通过将视频切分成多个小片段,并生成一个M3U8播放列表文件,实现低延迟和高稳定性。本文详细介绍了如何将TS文件转换为M3U8直播流,包括技术原理和具体操作步骤,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 本文深入探讨了Hibernate框架中乐观锁和悲观锁的机制及其多态特性。乐观锁假设数据在大多数情况下不会发生冲突,因此在读取数据时不加锁,而是在更新时检查版本号以确保数据未被修改。相比之下,悲观锁则认为数据在并发环境下容易产生冲突,因此在读取数据时立即加锁,以防止其他事务访问同一数据,从而避免潜在的数据不一致问题。文章还详细分析了这两种锁机制在实际应用中的优缺点,并介绍了Hibernate中的多态特性如何与锁机制结合,以实现更高效的数据管理和并发控制。 ... [详细]
  • 深入解析 SQL 数据库查询技术
    本文深入探讨了SQL数据库查询技术,重点讲解了单表查询的各种方法。首先,介绍了如何从表中选择特定的列,包括查询指定列、查询所有列以及计算值的查询。此外,还详细解释了如何使用列别名来修改查询结果的列标题,并介绍了更名运算的应用场景和实现方式。通过这些内容,读者可以更好地理解和掌握SQL查询的基本技巧和高级用法。 ... [详细]
author-avatar
zulaka_208
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有