《Data Warehouse Toolkit》:第三章,零售销售

四步维度建模流程

第1步:选择业务流程

第2步:声明粒度

第3步:确定维度

第4步:确定事实

通过回答问题“流程中测量什么?”来确定事实。业务人员对分析这些表现指标是非常有兴趣的。所有设计当中的候选事实都必须符合第2步中定义的粒度。那些很明显属于不同粒度的事实必须放在不同事实表中。典型的事实是数值可加的数字,例如订购的数量或者美元的花销。

深入数据而不面谈业务人员好像没有那么可怕;然而,数据不能替代业务人员的输入。不幸的是,很多组织都尝试过这条阻力最小的道路的数据驱动方案,不过成效有效。

销售案例研究

数据在基础杂货店里的几个有趣的地方被收集。其中最有用的数据是在顾客购买商品时在收银台被收集的。在收银台,零售终端(POS)系统扫描商品的条形码,计量顾客取走的商品。其他数据在店铺的后门

第1步:选择业务流程

第2步:声明粒度

第3步:确定维度

第4步:确定事实

衍生事实

通过从扩展销售金额中减去扩展成本金额可以计算出来总利润,或者收益。尽管是被计算出来的,总利润是可以在所有维度上完全可加的;你可以计算在任意天数的内的任意店铺组合的任意所售产品组合的总利润。维度建模者有时会问是否被计算的衍生事实应该被存储到数据库中。我们一般推荐要将其实际地进行存储。因为总利润可以从一条事实表中的行中相临近的数据计算而来,所有有些人会认为应该在视图中执行这样的计算。如果所有的用户都通过视图来访问该数据,而不会有使用即席查询工具的用户偷偷绕过视图而直接使用物理表的话这也是一个合理的方案。然而,有时非可加度量,例如百分比或比率,是必须在BI应用中计算的,因为这类计算不能被预计算出来存储到事实表中的。

非可加事实

毛利除以扩展销售收入就是毛利率。毛利率是非可加的事实,因为不能沿着任何维度对它进行汇总。通过分别计算收入和成本的合计值,然后相除可以计算任何产品、店铺、或天数内的毛利率。

注意,百分比和比率,例如毛利率,是非可加的。分子和分母应该被存储到事实表中。

单价是另一个非可加的事实。不像事实表中的扩展的数量,对任何维度上对单价进行求和都是无意义的。在有些情况下,一个基本非可加事实,例如温度,是由源系统所提供的。

事务事实表

事务性的业务流程是最常见的。代表这类流程的事实表都有一些特性:

维度表细节

日期维度

标记和指示符作为文本属性

一天当中的时间是作为维度还是作为事实

商品维度

商品维度描述杂货店中的每个SKU。

扁平的多对一层级结构

对于每个SKU,其所有的商品层级都定义好了。有些属性是唯一的,例如SKU描述。这个例子中,在SUK描述这一列中有300,000个不同的值。另一个极端,部门描述可能只有50个不同的取值。这样的话,部门描述中的每个取值平均会重复6,000次。这是完全可以接受的!不需要将这些被重复的值单独抽取到第二个规范化的表以节省空间。

商品维度表中通常会有不只一个显示的层级。

带有内在含义的属性

操作商品码(维度表中NK符号所表示的自然键)有内在的含义,其中码的不同部分代表着商品的重要特性。这种情况下,这个复合属性应该被作为整体保留下来,并且将其拆分为多个部分,每个部分作为单独的属性来处理。例如,如果操作码的第5个到第9个字符代表的是厂商,那么厂商的名字应该作为维度表的属性被保存。

数值作为属性还是作为事实

一个典型的例子是:商品的标准定价。这肯定是数值,所以第一直觉是将其放到事实表中。但是,一般标准价格很少变化,不像大部分事实它们在每个测度事件上的值都不同。

如果数值主要用于计算的目的,那么它可能属于事实表。或者,如果标准价格主要用于价格差异分析,。如果稳定的数值主要用于过滤和分组,那么它应该被当成商品维度属性。

有时,数值充当计算和过滤/分组的功能。这时,应该将该值存储到事实表和维度表中。假定,事实表中的标准价格表示的是在销售事务发生时的值,而维度属性表示的是它当前的标准价格。

在维度属性上进行下钻

店铺维度

维度表中多个层级

维度表中的日期

促销维度

这种维度通常被称为因果维度,因为它描述的是造成商品销售中变化的因素。

例如,在一次促销当中,大部分店铺会同时执行三种促销机制,但是有的店铺可能不安装收银处的通道终端显示器。这种情况,需要两条单独的促销条件行,一行是正常降价加上广告加上显示器,一行正常降价加上广告。

从纯逻辑的角度来看,可以将这些促销的类似信息通过划分成独立的四种因果机制将它们记录到不同的维度中,而不是将它们组合到一个维度中。支持将四个维度放到一起的权衡有:

  • 如果这四种因果机制是高度相关的,那么这个合并的维度不会比任何一个单独的维度要大。
  • 合并的维度可以被高效浏览以查看不同的降价、广告、以及优惠券是如何被一同使用的。然而,这种浏览只能显示可能的促销组合。

支持将四个维度独立到四个不同维度表中的权衡有:

  • 如果用户,独立的维度对于企业更好理解,

空的外键、属性、事实

通常,很多销售事务中包含有没有进行促销的商品。顾客不会只在购物车中装促销的商品;顾客需要为购物车中有些商品支付全价!促销维度必须要包含一行(唯一键为0或-1)来识别这种不促销的条件,这样可以避免事实表中空的促销键。如果你将null放到事实表中声明为到维度表外键的列,就违反了参照完整性。除了参照完整性的警示,空值键对于使用方而言也是困惑的源头,因为它们不能在空值键上进行join。

我们有时也遇到过空值的维度属性值。这通常发生在当一个维度行还没有被完全填充好、或者有些属性不适用于所有的维度行的时候。不管是那种情况,我们都建议使用描述行的字符串,例如Unknown or Not Applicable,来替换空值。

最后,我们也会遇到事实表中度量是空的。我们通常会保留这些null值,这样它们可以在聚合函数中被正确的处理,例如,SUM、MIN、MAX、COUNT、AVG,这些函数针对null值都可以做出正确的事情。

其他的零售销售中的维度

在真实世界中,支付方式通常呈现出更为复杂的场景。如果在一次POS交易中支持多种支付方式,那么支付方式在声明的粒度上呈现出来的就不只一个值了。不要将所声明的粒度修改成不自然的粒度,例如POS交易中每个商品的每个支付方式一行;你可能要在单独的事实表中来捕获支付方式,粒度可以是每个交易一行(然后,不同的支付方式项作为不同的事实出现)或者每个交易的每种支付方式一行(这要求每个支付方式维度与每行进行关联)。

针对交易编号的退化维度

尽管POS交易编号看上去像事实表中维度键,这种本可能成为交易维度的描述性项被剥夺了。因为结果维度是空的,我们把POS交易编号成为退化维度。自然业务票据码,例如POS交易编号,置于事实表中而不用连接到维度表。退化维度经常出现在当事实表的粒度代表的着一次交易或一个交易行,因为退化维度表示了交易的唯一标识符。订单编号、发票号码、以及提单编号几乎总是以退化维度出现在维度建模中。

退化维度在事实表主键中经常扮演的是不可或缺的角色。在我们的案例学习中,零售销售事实表的主键是由:退化POS交易编号和商品组件组成的,假设扫描的相同商品被归到一个记录行。

注意,业务交易控制编码,例如订单编码、发票编码、以及提单编码通常会造成空的维度,这些编码一般会作为交易事实表的退化维度。退化维度是没有相应维度表的维度键。

零售模型实战

零售模型的扩展性

无事实事实表

维度表和事实表中的键

维度表中的代理键

维度表中唯一主键应该是代理键,而不应该依赖业务系统标识符(称为自然键)。代理键是根据需要按顺序分配到给维度的简单整数。第一条商品行被分配商品代理是1,下一条商品行被分配商品键2,依此类推。实际的代理键的值没有业务含义。代理键仅仅服务于连接维度表和事实表。

使用代理键有几点优势:

  • 缓冲数据仓库免受业务变化影响:代理键可以让数仓团队来掌控DW/BI环境,而不受由于要生成、更新、删除、回收、以及再利用商品编码的业务规则所鞭打。很多组织当中,历史业务码(例如,不活跃的账号或很老的商品码)在一段时间蛰伏后会被重新分配。如果账号在12个月不活跃后被回收,业务系统。但是DW/BI系统会为数据保留很多年。代理键为数仓提供了一种机制来区分有着相同业务账号的两个不同实例。
  • 集成多个源系统:
  • 提高性能:
  • 处理null或未知的条件:如之前提到的,特定的代理键值用于记录可能没有业务码的维度条件,例如,No Promotion条件或匿名客户。尽管这些业务码缺失了,你也可以为它们分配一个代理键。
  • 支持对维度属性变更进行追踪:

维度的自然键和耐用超自然键

退化维度中的代理键

尽管代理键通常不会分配给退化维度,但每种情况都需要具体评估来决定是否需要这样做。

  • 如果业务控制的数码不能做到跨区域唯一,这时就需要利用代理键。例如,零售的POS系统可能分配的业务码不是跨店唯一的。
  • 当控制码到达最大值时,系统可能会回零,然后重新使用以前的控制码。
  • 最后,取决于BI工具的能力,你可能需要分配代理键在事务码上进行交叉探寻。

日期维度中的巧妙键

尽管yyyymmdd代表的整数是日期维度键最常用的方案,但是有些关系型数据库的优化器更喜欢是一个真正的日期类型列来进行分区。这时,优化器知道在3月1日和4月1日之间有31个值,而不是20130301和20130401之间的100个值。这种智能会影响优化器所选择的查询策略,进而进一步将其查询时间。如果优化器会结合日期类型智能,那么应该考虑日期类型的键。如果使用日期类型键的唯一原因只是简化DBA的工作,那么就没那么大吸引力了。

事实表中的代理键

尽管我们坚定不移在维度表中使用代理键,但是我们很少要求在事实表中使用代理键。

好处:

  • 迅速识别唯一性。
  • 回退或重新开始批量装载。
  • 使用insert+delete替代update。
  • 使用事实表中的代理键作为parent/child模型中的引用。

抵御规范化

使用规范化维度的雪花模型

维度表规范化被称为雪花化。

雪花化湿维度建模的合理化延伸,然而,我们鼓励你抵御雪花模型,给出的两个主要设计驱动力:易用和性能。

  • 大量雪花化的表带来的是更加复杂的呈现。

支架

尽管我们通常不建议雪花化,但是有些情况下允许创建支架维度,将其附着在,。在这个例子中,被移走的支架是一个从主维度中雪花化出来的日期维度。支架日期维度中的属性被陈属性地、唯一性地进行标记来区别于与业务流程相关的其他日期。该维度只用于支撑主维度表中的日期属性,如果业务想要对这个日期属性按照非标准的日历属性(如,按财务周期、业务日期指标、或节假日)进行过滤和分组。否则,你只需在商品维度上将日期属性作为标准的日期类型列就可以了。

有太多维表的事实表就像多足蜈蚣