我知道在数据仓库维度中使用代理键是有充分理由的。尽管如此,我还是不明白如何将它们链接到事实表的外键。在事实表中,我只有在ETL过程中提取的自然密钥。原始数据库表中不存在代理密钥。对此有什么建议吗?感谢
下面有几个"请参阅"参考资料。这是我在Stack Overflow上的第一个答案,所以我还没有足够的信誉点来向您提供链接。如果你在维基百科上查找这些术语,它们会比我更雄辩地描述这些事情
在我使用过的数据仓库中,我们通常存储引用事实表中各种维度的代理键。事实上,除非在特殊情况下(例如退化维度),否则我会避免将源系统的自然键存储在事实表中。这有几个原因:
- 联接效率-一些源系统可能不使用简单的整数键;使用代理键可以降低这种复杂性,从而使数据仓库查询性能更好,因为它只需要处理单列整数联接。
- 从源系统中提取事实表;事实表可能比特定的源系统(或源系统的版本)更长寿,或者事实可能来自具有不同自然键的不同源系统。不管自然键设计如何,事实表和维度表之间的关系都保持不变
- 准确高效的时间点事实-如果维度中属性的历史记录很重要,则可以使用代理项来存储维度行的历史副本,并将更正版本附加到事实表行(请参阅慢慢更改维度;尤其是类型2)
- 维度可以由来自多个源系统的多个事实表使用,也可以从多个来源系统合并,在这种情况下,源系统自然键和维度代理键之间不会有简单的关系(请参见一致维度)
- 未知-有时您可能会遇到自然键为NULL、无效值或某些奇怪的情况。通过在维度表中设置一个或多个特殊行来表示"未知"、"无效"、"尚未发生"或其他适当的行,可以表示该条件,并在数据库中保持引用完整性。(从技术上讲,NULL值不可能是密钥,但一些数据库引擎会以牺牲数据仓库的性能和可用性为代价,让你逍遥法外)
- 我肯定我忘了一些非常重要的事情
通常,在加载事实表的转换阶段,我查找来自源系统的自然密钥的代理密钥,然后将代理密钥存储在事实表中,而不是自然密钥。我不知道你在哪个平台上,你可以在大多数数据库平台上使用JOIN来实现这一点。我经常在Microsoft SQL Server平台上使用SSIS查找。
代理密钥分配是在加载事实表的ETL过程中实现的。
使用专用映射表将自然密钥(例如产品代码ABSFG-QXYX-12673726)映射到通常为整数(例如1238)的代理密钥。
代理密钥很有用,应该在以下场景中部署:
-
自然密钥是可变的,即尽管自然密钥发生了变化,但您仍需要使用相同的代理密钥进行报告
-
自然密钥可以重复使用,即您获得相同的自然密钥,但必须将其报告为新实体
-
自然密钥是不愉快的,例如超长哈希代码,这可能会对存储、联接或排序造成问题
在某些用例中,代理密钥的使用应该受到严格质疑:
-
自然密钥(例如从源系统提取的密钥)是已经代理(例如序列生成的密钥)
-
源系统无法提供有关自然密钥的附加信息(例如更改或重用信息);即代理密钥将有效地是自然密钥的1:1映射。
-
切勿将代理项用于时间维度,尤其是当事实表按时间进行范围分区时(因为代理项会禁用范围分区修剪)。
代理密钥也有其缺点
-
它需要ETL过程中的映射(性能)
-
最终报告可能需要反向映射到自然密钥(性能)
-
一致性–如果出现"未知"自然密钥,则必须处理到代理密钥的映射失败的情况。您应该拒绝事实记录,还是因为映射表(不完整)的问题?
-
当然,代理密钥映射中的ETL错误可能会导致问题…
因此,为了总结,我会说是的,使用代理密钥是有充分理由的,但不使用代理密钥也有充分理由。您应该始终仔细检查源系统的接口,对于每个维度键,检查使用代理键的利润是否高于成本
要严格回答"如何将它们链接到事实表的外键"这个问题,您应该首先通过分配代理密钥来加载维度,然后通过按业务密钥查找维度来加载事实,并定位代理密钥并使用它来存储事实。或者,在维度延迟到达的情况下,如果在事实加载时无法按业务键找到维度成员,则使用业务键创建维度成员,并使用指定的代理键。稍后,当维度成员到达DWH时,只需更新其中的附加属性
从实践的角度来看,如果不需要接近实时的DWH,或者如果你每天只更新两次DWH,例如每晚和午餐时间,并且从头开始重新加载只需要几分钟,如果你的主要事实表只有几百万条记录,那么就不用麻烦代理密钥了。在实践中,如果你有巨大的工作量和数百万的事实,这是很好的。你可以通过阅读这篇文章来获得一些见解https://technet.microsoft.com/en-us/magazine/2008.04.dwperformance.aspx
如果你想利用真正大的DWH,例如大规模并行DWH或Hadoop技术,那么你应该将代理密钥更改为哈希密钥,以最大限度地减少数据移动,避免数据偏斜,并提供平衡的执行。