草庐IT

增量表、全量表、拉链表的应用场景及优缺点详解

Yale曼陀罗 2023-05-09 原文

增量表、全量表、拉链表的应用场景及优缺点详解

一、绪论

作为一名数据分析师,想要进行数据分析,首先要学会准确地获取数据,数据来源于数据库表,想要获取数据就需要知道库表的存储位置、存储形式等信息。一般来说,公司对于表的命名都有统一规范,比如:(1)表明数据存储于哪些库,是数据接入层还是数据明细层?是数据聚合层还是数据应用层?这些层分别对应于哪些库,命名是什么。(2)包含业务线、业务主题、表名、更新周期是什么。

二、维度表、事实表的定义及区分

维度表: 业务过程的业务实体 ,如:商品,用户,订单。

维度表中常见的column字段包含:

  • 代理键(自增列,可以充当主键)
  • 自然键(唯一区分,商品id,订单id)
  • 维度属性(商品的大小,颜色等)

事实表: 业务内特定事件的数据(大量的行) ,如:商品的销售记录。

事实表的常见分类包括: 全量表 增量表 流水表拉链表

接下来,我们将重点介绍什么是全量表、增量表、快照表和拉链表。

表的命名规范:
\quad
表中常见的isa,分别代表增量表快照表全量表

三、增量表、全量表、拉链表的定义

3.1 全量表

全量表: 记录更新周期内的全量数据,无论数据是否有变化都需要记录;

全量表的典型特征:

  1. 存储的是截至到目前最新状态的全部记录,有无变化,都要上报;
  2. 每次上报的数据都是所有的数据(变化的 + 没有变化的);
  3. 没有分区,所有数据存储在一个分区中。比如:今天是24号,那么全量表里面包含的数据是截至23号的所有数据,每次往全量表里面写数据都会覆盖之前的数据,所以全量表不能记录历史的数据情况,只有截止到当前最新的、全量的数据。

全量表的典型范例:

举个例子,2021年3月13号的全量表如图,当天有两位用户,其支付状态都是待支付。

2021年3月14号,uid为1的用户支付了,且当天新增了一位已支付的uid为3的用户,那么2021年3月14号的全量表就变成了下图,13号uid为1的用户待支付状态更新为已支付。

3.2 增量表

增量表: 记录更新周期内的新增数据,即在原表中数据的基础上新增本周期内产生的新数据,没变化的数据不会被记录;

增量表的典型特征:

  1. 增量表是相对于全量表而言的,增量表是每次把新增的数据追加到原表中;
  2. 记录每次增加的量,而不是总量(只报变化量,无变化不用报);
  3. 存在分区,增量表中每次新增的数据单独存储在一个分区中,历史分区中的数据记录不发生变化。

增量表的典型范例:

增量表,就是记录每天新增数据的表。比如:从24号到25号新增了哪些数据,改变了哪些数据,这些都会存储在增量表在25号的分区里面。

增量表和快照表中【分区时间】分别代表什么?
\quad

  1. 快照表中时间分区 t t t 日,实际代表第 t + 1 t+1 t+1日,例如:快照表中的25号分区和24号分区实际时间分别对应26号和25号),它俩的数据相减就是实际时间25号到26号有变化的、增加的数据,也就相当于增量表里面25号分区的数据。
  2. 增量表中时间分区 t t t 日,实际代表第 t t t 日。
    \quad

流量和存量的定义与区别:
\quad

  • 流量: 是指在一定时间内的增量,流量一般设计成增量表(日报-常用、月报);
  • 存量: 是指在一定时间内的总量,存量一般设计成总量表;
  • 流量和存量的区别: 流量是增量,存量是总量

3.3 快照表

快照表: 就是截至过去某个时间点的所有数据,主要对过去某个时间点的数据状态进行记录,即:快照表主要存储的是历史状态的表,每个快照的数据单独存储在一个分区中。

快照表的适用场景:

为解决全量表无法查询历史数据的情况,引入了快照表。快照表是有时间分区的,每个分区里的数据都是分区时间对应的前一天的所有全量数据,比如:当前数据表有3个分区,24号、25号、26号。其中,24号分区里面的数据就是从历史到23号的所有数据,25号分区里面的数据就是从历史到24号的所有数据,以此类推。

快照表的典型特征:
按照时间分区进行数据存储;

快照表的优缺点:

  • 优点:可实现对历史数据的查询;
  • 缺点:数据量大时,由于每个分区都存储了许多重复数据,非常浪费存储空间。

快照表的典型范例:

快照表用来存储截止过去某个时间点的所有数据,比如:一些用户特征的表、标签表、订单状态表等多存储于快照表中,其实快照表也有所区分,本质是一段时间内数据的记录,主要还是看底层报表开发人员的逻辑。

  1. 有些快照表某分区的数据是从历史到此分区前一天的所有数据,如:12号分区中的数据是从历史到11号的所有数据,13号分区中的数据是从历史到12号的所有数据,其他的以此类推。
  2. 有些快照表某分区的数据是从历史到此分区的所有数据,如:12号分区中的数据是从历史到12号的所有数据,13号分区中的数据是从历史到13号的所有数据,其他的以此类推。

日常工作中我们也会经常用到快照表,以前不懂的时候就取好几个分区,导致取了大量且重复的数据,实际上快照表最近的一个分区就存储了从历史到当前分区的所有数据,我们只需要取一个分区就可满足取数需求。

3.4 流水表

流水表: 对于表的每一个修改都会记录,可以用于反映实际记录的变更。

流水表的典型特征:

  1. 流水表是存储了所有修改记录的表。
  2. 流水表是每天的交易形成的历史;
  3. 流水表用于统计业务相关情况
  4. 流水表与拉链表也有些类似,不同的是拉链表可以根据拉链粒度存储数据,也就是只存储特定维度的数据变化记录;而流水表存储的是每一个修改记录拉链表与流水表的区别)。

3.5 拉链表

鉴于全量表、快照表的缺点,为了在保留所有状态的情况下,有效节省存储空间,引入了拉链表。

3.5.1 拉链表的基本属性

拉链表: 是一种维护历史状态,以及最新状态数据的一种表,记录数据从开始一直到当前状态所有变化的信息

拉链表的典型特征:

  1. 记录一个事物从开始,一直到当前状态的所有变化的信息;
  2. 拉链表每次上报的都是历史记录的最终状态,是记录在当前时刻的历史总量;
  3. 拉链表通常是对账户信息的历史变动进行处理保留的结果
  4. 拉链表用于统计账户及客户的情况
  5. 拉链表和增量表的共同点表结构基本一样
  6. 与快照表类似,但拉链表存储的是在快照表的基础上去除了重复状态的数据,也就是说一些不变的信息在快照表中每个分区都会存储一份,可能造成存储浪费,而使用拉链表在更新频率和比例不是很大的情况下会十分节省存储。( 拉链表与快照表的区别)。
  7. 拉链表的封链时间可以是2999,3000,9999等等比较大的年份;拉链表到期时数据要报0;

拉链表的适用场景:

当数据量较大,表中某些字段有变化,但变化频率不是很高,而业务需求又需要统计这种变化状态,如果每天存储一份全量数据,不仅浪费存储空间,且不便于业务统计;这时,拉链表的作用就体现出来了,既节省空间,又满足需求。

在数据仓库的数据模型设计过程中,经常会遇到这样的需求:

  1. 数据量比较大;
  2. 表中的部分字段会被update,例如:用户的地址、产品的描述信息、订单的状态等等;
  3. 业务需要:(1)查看某一个时间点或者时间段的历史快照信息,比如:查看某一个订单在历史某一个时间点的状态;(2)统计订单信息的变化频次,比如:查看某一个用户在过去某一段时间内,更新过几次等等;
  4. 信息变化的比例和频率不是很大,比如:总共有1000万会员,每天新增和发生变化的有10万左右;

此时,如果对张表每天都保留一份全量,那么每次全量中会保存很多不变的信息,这对存储是极大的浪费;拉链表,既能满足反应数据的历史状态,又能最大程度地节省存储空间。

拉链表的优缺点:

  • 优点:(1)保留了数据的历史信息;(2)节省存储空间;
  • 缺点:同步和回滚逻辑复杂;

3.5.2 拉链表的典型范例

拉链表的典型范例:

举个简单例子,比如有一张订单表,6月20号有3条记录:

订单创建日期订单编号订单状态
2012-06-20001创建订单
2012-06-20002创建订单
2012-06-20003支付完成

到6月21日,表中有5条记录:

订单创建日期订单编号订单状态
2012-06-20001支付完成(从【创建订单】update到【支付完成】)
2012-06-20002创建订单
2012-06-20003支付完成
2012-06-21004创建订单
2012-06-21005创建订单

到6月22日,表中有6条记录:

订单创建日期订单编号订单状态
2012-06-20 001 支付完成(从【创建订单】update到【支付完成】)
2012-06-20002创建订单
2012-06-20003 已发货(从【支付完成】update到【已发货】)
2012-06-21004创建订单
2012-06-21005 支付完成(从【创建订单】update到【支付完成】)
2012-06-22006创建订单

数据仓库中对该表的保留方法:

  1. 只保留一份全量,则最终的表数据和6月22日的记录一样,如果需要查看6月21日订单001的状态,则无法满足;
  2. 每天都保留一份全量,则数据仓库中的该表共有14条记录,但好多记录都是重复保存,没有任何变化,例如:订单002、004,数据量大了,会造成很大的存储浪费;

如果在数据仓库中设计成 历史拉链表 来保存数据,则会有下面这样一张表:

一般在数仓中通过增加dw_begin_datedw_end_date两个字段来表征 历史拉链表

订单创建日期订单编号订单状态dw_begin_datedw_end_date
2012-06-20001创建订单2012-06-202012-06-20
2012-06-20001支付完成2012-06-219999-12-31
2012-06-20002创建订单2012-06-209999-12-31
2012-06-20003支付完成2012-06-202012-06-21
2012-06-20003已发货2012-06-229999-12-31
2012-06-21004创建订单2012-06-219999-12-31
2012-06-21005创建订单2012-06-212012-06-21
2012-06-21005支付完成2012-06-229999-12-31
2012-06-22006创建订单2012-06-229999-12-31

表中的字段及使用说明:

  • dw_begin_date:表示该条记录的生命周期开始时间
  • dw_end_date:表示该条记录的生命周期结束时间
  • dw_end_date = ‘9999-12-31’表示该条记录目前处于有效状态
  • 拉链表可以记录一条数据从开始到当前的所有历史信息,便于查询历史数据。
  1. 如果查询当前所有有效的记录,则select * from order_his where dw_end_date = ‘9999-12-31′
  2. 如果查询2012-06-21的历史快照,则select * from order_his where dw_begin_date <= ‘2012-06-21′ and end_date >= ‘2012-06-21’,这条语句会查询到以下记录;
  3. 通过dw_end_date过滤2020-06-02之前的旧数据;
  4. 通过dw_begin_date过滤2020-06-02之后的新数据。
订单创建日期订单编号订单状态dw_begin_datedw_end_date
2012-06-20001支付完成2012-06-219999-12-31
2012-06-20002创建订单2012-06-209999-12-31
2012-06-20003支付完成2012-06-202012-06-21
2012-06-21004创建订单2012-06-219999-12-31
2012-06-21005创建订单2012-06-212012-06-21

和源表在6月21日的记录完全一致:

订单创建日期订单编号订单状态
2012-06-20001支付完成(从【创建订单】update到【支付完成】)
2012-06-20002创建订单
2012-06-20003支付完成
2012-06-21004创建订单
2012-06-21005创建订单

可以看出,这样的历史拉链表,既能满足对历史数据的需求,又能很大程度的节省存储资源

参考链接:

1、真正秒懂增量表、全量表和拉链表

2、MySQL实现拉链表操作——hive中拉链表

3、一文搞定数据仓库之拉链表,流水表,全量表,增量表

4、数据仓库数据模型之:极限存储–历史拉链表

5、拉链表

6、拉链表(二)

3.5.3 拉链表的使用方法

拉链表的使用方法:

  1. 准备好两个表:全量表和增量表(备注:(1)全量表记录数据的历史状态;(2)增量表记录数据的增量信息);
  2. 更新流程:关联全量表和增量表,修改增量表中出现的数据行的失效时间,即:合并增量表和修改后的全量表;

按照每天存放的数据以及是否按天分区,增量表,全量表和快照表

全量表增量表快照表
包含从开始到前一天的全量数据包含前一天的增量数据包含前一天的全量数据
分区不分区(ymd为当前日期)按照每一天进行分区

四、如何选择该使用全量表、增量表、拉链表、快照表?

  1. 总体而言,在数据量不是很大的情况下是可以优先考虑使用全量表进行数据存储,该方法简单,但会很耗资源。

  2. 一般,建议使用增量表进行存储,毕竟目前大多数公司的数据量都很大,且数据量都在不断增长。

  3. 当遇到历史状态需要保存的时候就需要使用快照表和拉链表了,比如:上面提到的一些标签、用户特征、订单状态等。

参考链接:你应该知道的全量表、增量表、快照表、拉链表

有关增量表、全量表、拉链表的应用场景及优缺点详解的更多相关文章

  1. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  2. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  3. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  4. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  5. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  6. ruby-on-rails - 如何在 Gem 中获取 Rails 应用程序的根目录 - 2

    是否可以在应用程序中包含的gem代码中知道应用程序的Rails文件系统根目录?这是gem来源的示例:moduleMyGemdefself.included(base)putsRails.root#returnnilendendActionController::Base.send:include,MyGem谢谢,抱歉我的英语不好 最佳答案 我发现解决类似问题的解决方案是使用railtie初始化程序包含我的模块。所以,在你的/lib/mygem/railtie.rbmoduleMyGemclassRailtie使用此代码,您的模块将在

  7. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  8. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  9. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  10. ruby-on-rails - 从应用程序中自定义文件夹内的命名空间自动加载 - 2

    我们目前正在为ROR3.2开发自定义cms引擎。在这个过程中,我们希望成为我们的rails应用程序中的一等公民的几个类类型起源,这意味着它们应该驻留在应用程序的app文件夹下,它是插件。目前我们有以下类型:数据源数据类型查看我在app文件夹下创建了多个目录来保存这些:应用/数据源应用/数据类型应用/View更多类型将随之而来,我有点担心应用程序文件夹被这么多目录污染。因此,我想将它们移动到一个子目录/模块中,该子目录/模块包含cms定义的所有类型。所有类都应位于MyCms命名空间内,目录布局应如下所示:应用程序/my_cms/data_source应用程序/my_cms/data_ty

随机推荐