理论与实践的一个典型区别就是,现实世界中我们遇到的问题总是不按套路来,一切都在不断变化。或者说这个世界没有我们遇不到的问题, 只有我们想不到的变化。
面对数据仓库,我们源源不断地将数据往里面扔,力求建造一个数据帝国,新时代的知识库。自然,IT做的最多的莫过于“插”这档子的事。但IT也有容易火大的时候, 时不时就会有业务跑来说,哪个哪个变了,请IT帮忙搞一下,IT改完了,业务又跑来说改错了……这儿我们以维度表修改为例子。好在一般对维度表的修改频率不是很高,江湖上,维度建模门常把这种短暂不变的维表称为:缓慢变化维,字slowly change dimension, 号SCD。
应对这种缓慢变化的维度表的策略千变万化,非常灵活,但归根结底,无非是如下三招。
招式一:覆盖
使用新值直接覆盖旧值。这种方法,最简单,但也是对于历史数据最不负责任的招式。
比如说, 我们的IT正服务于某大型鞋服零售行业。ODS中有如下数据。
销售员工号 | 姓名 | 部门 |
21667046 | 金波 | 运动 |
日期 | 货号 | 牌价 | 数量 | 销售额 | 销售员工号 |
4/7/2011 | D32K080G | 1200.00 | 1 | 1200.00 | 21667046 |
4/7/2011 | P8892-XL | 800.00 | 2 | 1600.00 | 21667046 |
当然,这两个表里还有大量其它属性,在此我们简略一下。4月7号这天,隶属运动部门的金波卖了3双鞋(鞋服行业利润太高了)。业务跑来说,金波4月8号由运动部调到了女鞋的某个部门:
销售员工号 | 姓名 | 部门 |
21667046 | 金波 | 女鞋部 |
此时我们再查女鞋部的销售情况, 则金波原先在运动部门下做的销售单也归结到了女鞋部门的销售业绩下。
以上我们说的都是这招的弱点,如下再提及一下这种方式的适用条件:修正错误,假若金波本身是就是女鞋部的,但系统录入的却是“运动”,按这种说法,使用这招就无可厚非了。
招式二:添加维度行
直接新添一条记录,同时保留原有记录,并用单独的专用的字段保存区别。
首先原先具有业务含义的物理主键不再做主键,用一个没有任何业务含义的字段作为主键, 就是使用所谓的“代理主键”。其次, 很自然地可以在维度表中加入时间戳,便于更好的追踪历史信息。例如下二表:
销售员代号 | 销售员工号 | 姓名 | 部门 | 生效日期 | 截止日期 |
XI82738XI91 | 21667046 | 金波 | 运动 | 1990/01/01 00:00:0 | 2011/04/08 00:00:00 |
XI82738XI92 | 21667046 | 金波 | 女鞋部 | 2011/04/08 00:00:0 | 2999/12/31 00:00:00 |
日期 | 货号 | 牌价 | 数量 | 销售额 | 销售员代号 |
4/7/2011 | D32K080G | 1200.00 | 1 | 1200.00 | XI82738XI91 |
4/7/2011 | P8892-XL | 800.00 | 2 | 1600.00 | XI82738XI91 |
4/8/2011 | P8901-SL | 100.00 | 1 | 100.00 | XI82738XI92 |
4月8号, 业务要求将金波调至女鞋部, 则对应的维度表添加新行,新纪录中金波的销售员代号变为了XI82738XI92,部门变为女鞋部, 而本身的员工代号未变。这里也解释了为什么需要使用代理主键。 使用这个方式,招式一的缺陷被弥补了,历史数据被保留了下来。
特别说明下这个地方的两个时间戳,它们对事实表的日期处理并不会有多大作用。如销售软件的公司, 在5月1日发布某软件的新版本, 则需要添加一个新的维度行,但站在商店的角度,事情则没有想的那么生硬,货架上残存的旧版本,将继续卖下去,直到卖光为止。另一方面, 软件新版本都会提前在上市前到达店铺进行销售。换句话讲,维度表的日期与业务处理并没有太多的相关性。
多讲一句,有时候, 还会在维表中加入一个管理列,用作CRCs匹配。关于对代理关键字的管理, 后续将作介绍。
招式三:添加维度列
使用不同的字段保留变化轨迹。
招式二尽管已经能够将历史数据取出来,但仍有其麻烦的地方,不能将新属性值与历史属性值联系起来。添加“部门=‘女鞋部’”就不能看到金波在4月8号前, 运动部门的销售情况,但纵向数据往往也是业务需要查看的东西。针对这种需求,招式三可以提供支援。用招式三对于轨迹跟踪显得很方便。例如下表:
销售员代号 | 销售员工号 | 姓名 | 部门 | 前部门 |
XI82738XI91 | 21667046 | 金波 | 运动 | 运动 |
XI82738XI92 | 21667046 | 金波 | 女鞋部 | 运动 |
用一个新字段去维护历史信息。
笔者知道鞋服零售行业的Belle集团关于店铺维度就采用的这种策略。店铺的区域划分经常发生变化,抑或是同一家实体店,由于种种原因关闭,但后期开张,但会以一个新店号录入系统中。但业务还是希望能纵向追踪其轨迹。对此, 分销系统采用了一个“店铺代号2”作为历史数据的维护信息。不过滑稽的是,后期在belle开发BI系统时,一些专家一直抱怨分销设计中没有采用SCD。这个很让IT郁闷,[招事三]难道不是SCD吗。
不过招式三的弱点也很明显,不适合有大量中间值变化的case。基于这种使用限制,使用也极为少。如果需要追踪无穷无尽的变化,最适合还是招式二了。
总结
茫茫江湖,其它关于缓慢变化维的策略几乎都是以上三招的衍生体。诚然IT为了追求其自身价值,追求完美,往往希望能在设计时就扩展需求,留做备用。但这样毕竟增大了复杂度,工作量,搞得业务还火大,出力不讨好。IT难啊, 难IT啊。面对不同的问题,到底使用哪种,不好说,一切只要满足需求就行。