数据仓库拉链表是一种特殊的表结构,用于记录数据的历史变化、支持数据版本管理、提供数据追溯功能。其中,数据版本管理是数据仓库拉链表的一个关键功能。数据版本管理使得每一条记录都带有其生效和失效的时间戳,这样可以追踪到每条记录在某个时间点的状态。通过这种方式,用户可以查询到任何时间点的数据状态,极大地增强了数据分析的灵活性和准确性。

例如,在客户关系管理(CRM)系统中,通过拉链表可以追踪到客户信息在不同时间的变更情况,从而进行更加精准的营销和客户服务。

数据仓库拉链表的概念

数据仓库拉链表是一种用于记录数据历史变化的特殊表结构,通常用于数据仓库系统中。其主要特点是每条记录都带有生效和失效的时间戳。通过这种方式,可以记录数据在不同时期的状态,支持数据的追溯和版本管理。拉链表的设计旨在解决传统数据表不能很好地记录历史数据的问题,使得数据分析更加精确。

定义: 数据仓库拉链表也称为“缓慢变化维表(Slowly Changing Dimension Table)”中的一种实现方式,通常用来处理维度数据随时间变化的情况。

结构特点: 每条记录带有两个时间戳字段:生效时间和失效时间。生效时间表示记录何时开始有效,失效时间表示记录何时失效。对于当前有效的记录,失效时间通常设置为一个未来的日期,如 '9999-12-31'。

用途: 拉链表主要用于需要保留历史数据的场景,如客户信息管理、产品价格变动记录、员工职位变动记录等。通过使用拉链表,可以方便地查询任意时间点的数据状态。

数据仓库拉链表的优势

  • 历史数据保留: 拉链表能够完整保留数据的历史变化,支持对历史数据的查询和分析。这对于需要进行时间序列分析、数据回溯的业务场景非常重要
  • 数据版本管理: 通过生效和失效时间戳,可以实现数据版本管理,方便追溯每条记录在不同时间点的状态
  • 数据一致性: 拉链表可以确保数据的一致性和完整性,避免数据丢失或重复
  • 灵活查询: 用户可以通过指定时间点查询数据的状态,支持更复杂的查询需求
  • 审计和监管: 拉链表能够提供详细的数据变更记录,满足审计和监管的需求

详细描述数据版本管理: 数据版本管理是拉链表的核心功能之一。每条记录的生效时间和失效时间字段,使得数据的每一次变更都可以被记录下来。例如,在客户信息管理中,当客户的地址发生变更时,拉链表会插入一条新记录,更新生效时间为变更后的日期,并将旧记录的失效时间设置为变更前的日期。这样,通过查询不同时间点的记录,可以清晰地看到客户地址的变更历史。这种数据管理方式不仅能够确保数据的完整性和一致性,还能够提供更详细和准确的历史数据分析。

数据仓库拉链表的设计原则

  • 字段设计: 拉链表的基本字段包括主键字段、业务字段、生效时间字段、失效时间字段。主键字段用于唯一标识记录,业务字段用于存储具体的业务数据,生效时间和失效时间字段用于记录数据的有效时间范围
  • 时间戳格式: 生效时间和失效时间通常使用日期时间格式(如 'YYYY-MM-DD HH:MM:SS'),以确保时间的精确性
  • 默认值设置: 对于当前有效的记录,失效时间通常设置为一个未来的日期(如 '9999-12-31'),表示记录当前有效
  • 数据更新策略: 在数据更新时,不直接修改现有记录,而是插入一条新记录,并更新旧记录的失效时间
  • 索引优化: 为了提高查询效率,可以对生效时间和失效时间字段建立索引
  • 数据归档: 对于较早的历史数据,可以定期进行归档,以减少拉链表的存储压力和查询开销

设计示例:

假设有一个客户信息表,需要记录客户地址的变更历史。

字段设计如下:

  • 客户ID(主键)
  • 客户姓名
  • 客户地址
  • 生效时间
  • 失效时间

记录示例如下:

客户ID 客户姓名 客户地址 生效时间 失效时间
1 张三 北京 2021-01-01 2021-06-30
1 张三 上海 2021-07-01 9999-12-31

在上述示例中,当客户地址从北京变更为上海时,插入一条新记录,并更新旧记录的失效时间。这种设计确保了客户地址变更的历史记录可以被完整保留和查询。

数据仓库拉链表的实现步骤

  • 需求分析: 确定需要使用拉链表的业务场景,明确需要记录的历史数据和时间范围
  • 表结构设计: 根据需求设计拉链表的字段,包括主键字段、业务字段、生效时间字段、失效时间字段
  • 数据初始化: 将现有数据导入拉链表,并设置初始的生效时间和失效时间
  • 数据更新逻辑: 编写数据更新逻辑,在数据变更时插入新记录,并更新旧记录的失效时间
  • 索引和性能优化: 对生效时间和失效时间字段建立索引,以提高查询性能
  • 数据归档和维护: 定期归档较早的历史数据,减少拉链表的存储压力,并进行必要的维护

数据仓库拉链表的应用场景

  • 客户关系管理(CRM)系统: 在 CRM 系统中,客户信息经常发生变更,如地址、联系方式等。通过拉链表,可以记录客户信息的历史变化,支持客户信息的追溯和分析
  • 财务系统: 在财务系统中,账目、预算等数据需要记录历史变化,以满足审计和监管的需求。拉链表可以完整记录财务数据的变更历史,支持财务数据的回溯和分析
  • 人力资源管理(HRM)系统: 在 HRM 系统中,员工职位、薪资等信息经常变更。通过拉链表,可以记录员工信息的历史变化,支持员工信息的追溯和分析
  • 供应链管理(SCM)系统: 在 SCM 系统中,供应商、库存等信息经常变更。通过拉链表,可以记录供应链信息的历史变化,支持供应链信息的追溯和分析
  • 产品信息管理(PIM)系统: 在 PIM 系统中,产品价格、规格等信息经常变更。通过拉链表,可以记录产品信息的历史变化,支持产品信息的追溯和分析。

数据仓库拉链表的常见挑战和解决方案

  • 数据量大: 随着时间的推移,拉链表的数据量会逐渐增大,影响查询性能。解决方案:可以定期归档较早的历史数据,减少拉链表的存储压力。此外,可以对生效时间和失效时间字段建立索引,提高查询性能
  • 数据更新复杂: 拉链表的更新逻辑较为复杂,需要插入新记录并更新旧记录的失效时间。解决方案:可以编写存储过程或触发器,自动处理拉链表的更新逻辑,减少人为操作的复杂性和错误率
  • 数据一致性: 在并发环境下,拉链表的数据一致性可能受到影响。解决方案:可以使用事务管理,确保数据更新的原子性和一致性。此外,可以使用行级锁定,防止并发更新导致的数据不一致
  • 查询复杂性: 由于拉链表记录了大量的历史数据,查询时需要考虑生效时间和失效时间,查询逻辑较为复杂。解决方案:可以通过视图或存储过程,简化查询逻辑,提高查询的可读性和可维护性
  • 存储成本: 拉链表需要记录大量的历史数据,存储成本较高。解决方案:可以定期归档较早的历史数据,减少拉链表的存储压力。此外,可以使用压缩存储技术,降低存储成本。

缓慢变化维(SCD)

缓慢变化维简介

  • 缓慢变化维,简称 SCD(Slowly Changing Dimensions)
  • 一些维度表的数据不是静态的,而是会随着时间而缓慢地变化(这里的缓慢是相对事实表而言,事实表数据变化的速度比维度表快)
  • 这种随着时间发生变化的维度称之为缓慢变化维
  • 把处理维度表数据历史变化的问题,称为缓慢变化维问题,简称 SCD 问题

SCD 问题的几种解决方案

改写属性值

  • 需要重写维度行中的旧值,以当前值替换。因此其始终反映最近的情况
  • 当一个维度值的数据源发生变化,并且不需要在维度表中保留变化历史时,通常用新数据来覆盖旧数据。这样的处理使属性所反映的是最新的赋值

例如:用户维度表

  • 修改前:
用户ID 用户名 出生日期 住址
114 张三 1988-09-08 北京市朝阳区
  • 修改后:
用户ID 用户名 出生日期 住址
114 张三 1992-09-08 北京市海淀区
  • 这种方法有个前提,用户不关心这个数据的变化
  • 这样处理,易于实现,但是没有保留历史数据,无法分析历史变化信息

增加维度新行

数据仓库系统的目标之一是正确地表示历史。典型代表就是拉链表。保留历史的数据,并插入新的数据。

例如:用户维度表

  • 修改前:
用户ID 用户名 出生日期 住址
114 张三 1988-09-08 北京市朝阳区
  • 修改后:
用户ID 用户名 出生日期 住址
114 张三 1988-09-08 北京市朝阳区
114 张三 1992-09-08 北京市海淀区

增加维度新列

用不同的字段来保存不同的值,就是在表中增加一个字段,这个字段用来保存变化后的当前值,而原来的值则被称为变化前的值。总的来说,这种方法通过添加字段来保存变化后的痕迹。

例如:用户维度表

  • 修改前:
用户ID 用户名 出生日期 住址
114 张三 1988-09-08 北京市朝阳区
  • 修改后:
用户ID 用户名 出生日期 住址 现住址
114 张三 1988-09-08 1992-09-08 北京市朝阳区 北京市海淀区

使用历史表

另外建一个表来保存历史记录,这种方式就是将历史数据与当前数据完全分开来,在维度中只保存当前最新的数据。

  • 用户维度表
用户ID 用户名 出生日期 住址
114 张三 1992-09-08 北京市海淀区
  • 用户维度历史表
用户ID 用户名 出生日期 住址
114 张三 1988-09-08 北京市朝阳区
114 张三 1992-09-08 北京市海淀区

这种方式的优点是可以同时分析当前及前一次变化的属性值,缺点是只保留了最后一次变化信息。

商品历史快照案例

需求:有一个商品表

列名 类型 说明
goods_id varchar(50) 商品编号
goods_status varchar(50) 商品状态(待审核、待售、在售、已删除)
createtime varchar(50) 商品创建日期
modifytime varchar(50) 商品修改日期

2019年12月20日的数据如下所示:

goods_id goods_status createtime modifytime
001 待审核 2019-12-18 2019-12-20
002 待售 2019-12-19 2019-12-20
003 在售 2019-12-20 2019-12-20
004 已删除 2019-12-15 2019-12-20

商品的状态,会随着时间推移而变化,我们需要将商品的所有变化的历史信息都保存下来。如何实现呢?

使用拉链表保存历史快照思路

  • 拉链表不存储冗余的数据,只有某行的数据发生变化,才需要保存下来,相比每次全量同步会节省存储空间
  • 能够查询到历史快照
  • 额外的增加了两列(dw_start_date、dw_end_date),为数据行的生命周期

12月20日商品拉链表的数据:

goods_id goods_status createtime modifytime dw_start_date dw_end_date
001 待审核 2019-12-18 2019-12-20 2019-12-20 9999-12-31
002 待售 2019-12-19 2019-12-20 2019-12-20 9999-12-31
003 在售 2019-12-20 2019-12-20 2019-12-20 9999-12-31
004 已删除 2019-12-15 2019-12-20 2019-12-20 9999-12-31

12月20日的数据是全新的数据导入到dw表

  • dw_start_date 表示某一条数据的生命周期起始时间,即数据从该时间开始有效(即生效日期)
  • dw_end_date 表示某一条数据的生命周期结束时间,即数据到这一天(即失效日期)
  • dw_end_date 为 '9999-12-31',表示当前这条数据是最新的数据,数据到 '9999-12-31' 才过期

12月21日商品拉链表的数据:

goods_id goods_status createtime modifytime dw_start_date dw_end_date
001 待审核 2019-12-18 2019-12-20 2019-12-20 2019-12-20
002 待售 2019-12-19 2019-12-20 2019-12-20 9999-12-31
003 在售 2019-12-20 2019-12-20 2019-12-20 9999-12-31
004 已删除 2019-12-15 2019-12-20 2019-12-20 9999-12-31
001(变) 待售 2019-12-18 2019-12-21 2019-12-21 9999-12-31
005(新) 待审核 2019-12-21 2019-12-21 2019-12-21 9999-12-31
006(新) 待审核 2019-12-21 2019-12-21 2019-12-21 9999-12-31

可以发现:

  • 拉链表中没有存储冗余的数据,(只要数据没有变化,无需同步)
  • 001 编号的商品数据的状态发生了变化(从待审核 → 待售),需要将原有的 dw_end_date 从 '9999-12-31' 变为 '2019-12-20' 表示待审核状态
  • 001 编号新的状态重新保存了一条记录,dw_start_date 为 '2019-12-21',dw_end_date 为 '9999-12-31'。新数据 005、006,dw_start_date 为 '2019-12-21',dw_end_date 为 '9999-12-31'

12月21日商品拉链表的数据:

goods_id goods_status createtime modifytime dw_start_date dw_end_date
001 待审核 2019-12-18 2019-12-20 2019-12-20 2019-12-20
002 待售 2019-12-19 2019-12-20 2019-12-20 9999-12-31
003 在售 2019-12-20 2019-12-20 2019-12-20 2019-12-21
004 已删除 2019-12-15 2019-12-20 2019-12-20 9999-12-31
001 待售 2019-12-18 2019-12-21 2019-12-21 9999-12-31
005 待审核 2019-12-21 2019-12-21 2019-12-21 9999-12-31
006 待审核 2019-12-21 2019-12-21 2019-12-21 9999-12-31
003(变) 已删除 2019-12-20 2019-12-22 2019-12-22 9999-12-31
007(新) 待审核 2019-12-22 2019-12-22 2019-12-22 9999-12-31
008(新) 待审核 2019-12-22 2019-12-22 2019-12-22 9999-12-31
  • 003 编号的商品数据的状态发生了变化(从在售→已删除),需要将原有的 dw_end_date 从 '9999-12-31' 变为 '2019-12-21',表示在售状态
  • 003 编号新的状态重新保存了一条记录,dw_start_date 为 '2019-12-21',dw_end_date 为 '9999-12-31'。新数据 007、008,dw_start_date 为 '2019-12-22',dw_end_date 为 '9999-12-31'

具体实现

拉链表的实现,参考如下资料: 基于 MaxCompute 实现拉链表

参考资料

数仓面试必问:缓慢变化维的处理

数仓--拉链表(原理、设计以及在Hive中的实现)

通俗易懂讲数据仓库之【缓慢变化维】

什么是数据仓库拉链表

原创文章,转载请注明出处:http://www.opcoder.cn/article/96/