草庐IT

详细记录拉链表的实现过程

atwdy 2025-02-10 原文

面试中被问到了,想了会儿思路混乱没答好,还是理解的不够深刻,重新好好理解记录一下~

拉链表的用途,主要是用来在数仓中记录业务库数据的全部历史信息和当前最新信息,也就是用来实现对渐变维的记录。数仓中对渐变维的记录通常有三种实现方式:

1)直接更新,也就是用业务库中发生变化的数据覆写数仓中的数据,这种实现方式可以保持数仓与业务库数据保持一致,缺点是只能保存当前最新的数据,对这条数据修改之前的历史数据不做维护,一般很少采用这种实现方式,除非历史数据本身就是错误的,没有使用价值。

2)通过在数仓中对经常发生变化的字段新增列来保存历史记录,比如用两个列来记录用户居住地这个属性,分别命名为previous_homecurrent_ home,当业务库中用户的居住地信息发生变化时,用current_home列来记录变化后的值,用previous_home列记录变化之前的值。这种记录方式能维护的历史变化记录数受限于新增列的个数,适合只需要保存最近的几个历史记录的业务场景。

3)也是常用的拉链表,拉链表可以实现对所有历史数据的维护,通过两个时间字段(例如start_dateend_date)实现对历史数据和当前最新数据的区分。

下面详细记录一下拉链表的实现过程

比如开始业务库中的数据:

第一次全量导入数仓ods层,然后以create_time作为拉链表中的start_date9999-01-01作为拉链表中end_date字段,导入到dwd层形成最初始的拉链表,像下面这样:

此时所有的记录end_date都为9999-01-01,表示为当前最新数据。

假设过了一天,业务库中的数据发生了变化,变成了下面这样:

也就是新增了赵六,同时李四的address修改为了北京,这个时候业务库数据导入ods层的时候就不必全量导入,只导入在28号这天发生了更改的数据,这里的更改包括新增和修改,导入条件设置为update_time between '2022-12-28 00:00:00' and '2022-12-28 23:59:59',此时同步到ods层的数据再以update_time为拉链表中start_date,同样以9999-01-01为拉链表中end_date字段,又得到了一张新的拉链表像下面这样:

此时这张拉链表就是只包含最新的记录信息,而上面那张拉链表中包含的既可能有最新的信息,也可能有历史的记录信息,此时我们需要把原始的那张拉链表中的end_date也就是数据的有效期修改一下,如果这条数据被更新了,那就将时间修改为发生更改的前一天,假设原始拉链表为A,新的拉链表为B:

select
	A.id,
	A.name,
	A.address,
	A.create_time,
	A.update_time,
	A.start_date,
	# B.id is not null说明匹配到的数据有更新,A.end_date='9999-01-01'限制只修改更新的这条数据在原始拉链表中最近的生效的这条记录,而不修改它的所有历史记录
	if(B.id is not null and A.end_date='9999-01-01', DATE_SUB(B.update_time, interval 1 day),'9999-01-01') as end_date
from A left join B on A.id = B.id;

得到的结果:

最后将修改过end_date的原始拉链表和上面那张新的拉链表做个union all操作就得到了最终的这张结果拉链表:

这张结果拉链表中既保存了业务库中最新的记录数据,又维护了李四修改前的历史数据。

后续对拉链表的更新都是只同步每天发生更新的数据,然后把这部分数据做成一个新的拉链表,再修改原始拉链表中的有效期end_date字段,然后两表union all就行了。

为了方便测试,数据都是在mysql中跑的,使用hive时稍微修改下部分语法和函数就行了,思路还是一样的。

有关详细记录拉链表的实现过程的更多相关文章

  1. ruby - Sinatra:运行 rspec 测试时记录噪音 - 2

    Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/

  2. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  3. ruby-on-rails - Rails 5 Active Record 记录无效错误 - 2

    我有两个Rails模型,即Invoice和Invoice_details。一个Invoice_details属于Invoice,一个Invoice有多个Invoice_details。我无法使用accepts_nested_attributes_forinInvoice通过Invoice模型保存Invoice_details。我收到以下错误:(0.2ms)BEGIN(0.2ms)ROLLBACKCompleted422UnprocessableEntityin25ms(ActiveRecord:4.0ms)ActiveRecord::RecordInvalid(Validationfa

  4. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  5. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  6. MIMO-OFDM无线通信技术及MATLAB实现(1)无线信道:传播和衰落 - 2

     MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO

  7. 在VMware16虚拟机安装Ubuntu详细教程 - 2

    在VMware16.2.4安装Ubuntu一、安装VMware1.打开VMwareWorkstationPro官网,点击即可进入。2.进入后向下滑动找到Workstation16ProforWindows,点击立即下载。3.下载完成,文件大小615MB,如下图:4.鼠标右击,以管理员身份运行。5.点击下一步6.勾选条款,点击下一步7.先勾选,再点击下一步8.去掉勾选,点击下一步9.点击下一步10.点击安装11.点击许可证12.在百度上搜索VM16许可证,复制填入,然后点击输入即可,亲测有效。13.点击完成14.重启系统,点击是15.双击VMwareWorkstationPro图标,进入虚拟机主

  8. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  9. ruby-on-rails - 事件记录 : Select max of limit - 2

    我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).

  10. ruby - Arrays Sets 和 SortedSets 在 Ruby 中是如何实现的 - 2

    通常,数组被实现为内存块,集合被实现为HashMap,有序集合被实现为跳跃列表。在Ruby中也是如此吗?我正在尝试从性能和内存占用方面评估Ruby中不同容器的使用情况 最佳答案 数组是Ruby核心库的一部分。每个Ruby实现都有自己的数组实现。Ruby语言规范只规定了Ruby数组的行为,并没有规定任何特定的实现策略。它甚至没有指定任何会强制或至少建议特定实现策略的性能约束。然而,大多数Rubyist对数组的性能特征有一些期望,这会迫使不符合它们的实现变得默默无闻,因为实际上没有人会使用它:插入、前置或追加以及删除元素的最坏情况步骤复

随机推荐