浅谈数据仓库中的缓变维度

虽然我的主要业务是实时计算和批量计算,不是点仓,但是日常工作中绝对要和点仓打交道。而且我参与过线下仓库建设,维度建模的基础不能忘。就把这篇文章当做抄笔记吧。

顾名思义,缓变维度(SCD)是指数据仓库维度表中那些随时间变化很小,但仍然变化的维度。考虑以下两种情况:

处理缓慢变化的维度是Kimball的数据仓库系统中一个永恒的话题。由于数据仓库的性质和维度表在维度建模中的基础作用,我们几乎总是要跟踪维度的变化,以保存历史并提供准确的查询和分析结果。在《数据仓库工具包》第3版第5章中,Kimball提出了缓变维度的多种类型和处理方法,其中前五种是原生的,后面的方法是混合技术,所以我们先来看看前五种,即0型~ 4型。

一种特殊的SCD类型,即无论维度属性的实际值如何变化,维度在数据仓库中的值都会保持第一个值。主要适用于那些含义为“原始”的维度,比如用户在用户维度表中注册时使用的原始用户名(original_user_name)。如果更改,更改后的值无效,将被丢弃。

最简单的SCD类型,即一旦维度属性的实际值发生变化,就会直接覆盖到数据仓库中。数据仓库中的维度属性总是保存最新的赋值。书中的例子如下:

在上图中,部门名称维度发生了变化,新值直接覆盖了以前的值。虽然它很容易实现,但它会丢失所有的更改历史,并且在跨时间域查询时可能会得到错误的结果。实际上,这种方法几乎总是一个糟糕的设计。

最重要和最常用的SCD类型是我们日常基于蜂巢的仓库构建中的拉链手表技术。

该类型在维度表中增加了两个辅助列:行的生效日期和失效日期,分别表示行从哪个时间点开始生效,从哪个时间点之后失效。每当一个或多个维度发生更改时,都会创建一个新行,其中包含已修改的维度值,而旧行包含未修改的维度值,旧行的到期日期也会同步修改。书中的例子如下:

在上图中,当前有效列(当前列)的失效日期将被记录为9999-12-31。当部门名称的维度发生变化时,产品关键字为12345的旧行的到期日期更新为修改日期,并创建一个关键字为25984的新行,其中包含新数据。

需要注意的是,这里的产品键就是所谓的代理键,即不代表具体的业务含义,只代表表中数据行的唯一ID。在处理SCD时,可以直接使用代理键来区分具有相同自然键的数据的新旧版本。上图中的SKU是自然键。

这种类型的SCD处理可以有效、准确地保留历史并反映变化,但缺点是会造成数据膨胀,因为即使只有一个维度发生变化,也会创建新的行。

虽然Type 2很好,但是当你想在同一个时间维度上关联新值和旧值的时候就没那么方便了。比如上一节的表中,如果查询2013年2月1之后的记录,只能找到部门名称为“策略”的记录,“学历”被屏蔽。类型3是与类型2互补的类型。在类型3的处理方法中,不会添加新的行,但会添加新的属性列,该列保存对应维度的最后更改值。书中的例子如下:

在上图中添加了一个名为“Prior Department Name”的列,它保存了最后更改的值。这也解决了Type 2的数据扩展问题,但只能保存一个变更历史,称为“交替现实”。

另外,还是要注意,如果维度表中的很多维度都会发生类似的变化,那么就会增加很多列,这显然是不靠谱的。因此,这种类型通常用于处理少量SCD,其变化是可预测的并且“影响全身”。

当然,你也可以根据实际需要添加多行来保存多次修改的历史:

当维度的变化不是那么“慢”的时候,前三种处理是不充分的(特别是对于非常大的维度表,比如几百万甚至几千万行)。一般这个维度不再叫SCD,而叫“快速变化维度”(RCD)。RCD规模比较小的时候,可以用2型或者3型支持,规模比较大的时候,只能用4型支持。Type 4的方式是把那些快速变化的维度从原来的大维度表中分离出来,单独处理,这是一个迷你维度。

以书的内容为例,如果客户维度中的一些人口统计维度是RCD,那么它们将被拆分到单独的维度表中:

其中,微维度表的维度最好是几个,带状的离散值,比如:

下表仍然来自原始数据仓库工具箱。注意,除了类型0 ~ 4,还有三种混合方式,即类型5 ~ 7。

最后,我善意地提醒你,《数据仓库工具箱》(第三版)这本书一定要看英文版,千万不要看中文版。中文翻译错误百出,很多地方读起来不通顺,令人窒息。

晚安那敏~