我和我们公司的另一位 DBA 的任务是审查供应商为我们开发的数据库设计。供应商表示他们使用 Kimball 作为他们设计的基础。(注意:我不是在寻找 Kimball 与 Inmon 等的论点。)他们设计了一个具有多个事实和维度的集市。
现在平心而论,我们公司从来没有设计过一个市场。我们一直让顾问来做这件事。而且我们从来没有被派去上课或其他任何事情。所以我们对仓储/集市/维度建模等方面的知识是基于我们所拥有的一些经验,我们可以在互联网上找到的,以及自学(我们有 Inmon 和 Kimball 的书,并且正在努力通过它们) .
现在舞台已经为我的知识水平做好了准备,我们来迎接设计挑战。
有一个名为“索赔损失统计”的事实表(这是用于保险的)。他们正试图获取索赔的付款(累积到每月的水平),然后是准备金中的钱(有点像索赔的银行账户)。他们希望看到每月的付款金额(没什么大不了的)。但他们希望看到准备金的账户当前余额。
我举个形象的例子。
假设我们为索赔设置了 1000 美元的准备金。这被搁置一旁(所以在某些方面它的功能有点像银行账户)。
2014 年 10 月,我们还没有支付任何费用。因此,企业希望在 10 月底看到付款和准备金余额。
-----------------------------------------------
- MONTH_YEAR - PAYMENTS - RESERVE_BALANCE -
-----------------------------------------------
- 102014 - 0.00 - 1000.00 -
-----------------------------------------------
然后十一月来了。我们支付 100 美元、150 美元和 75 美元的款项。他们希望看到这些合计金额和余额中的准备金如下:
-----------------------------------------------
- MONTH_YEAR - PAYMENTS - RESERVE_BALANCE -
-----------------------------------------------
- 102014 - 0.00 - 1000.00 -
-----------------------------------------------
- 112014 - 325.00 - 675.00 -
-----------------------------------------------
然后说我们在 12 月的付款为零,然后在明年 1 月再增加 200 美元。
-----------------------------------------------
- MONTH_YEAR - PAYMENTS - RESERVE_BALANCE -
-----------------------------------------------
- 102014 - 0.00 - 1000.00 -
-----------------------------------------------
- 112014 - 325.00 - 675.00 -
-----------------------------------------------
- 122014 - 0.00 - 675.00 -
-----------------------------------------------
- 12015 - 200.00 - 475.00 -
-----------------------------------------------
这是我挣扎的地方。我的理解是付款部分是正确的。它们都在每个记录中按月汇总。因此,如果您需要年度、季度等,您可以进一步汇总。
但储备金额不同。这是一种平衡。企业希望查看每个月的余额有多少。但是您不能在此字段上进行聚合。如果你这样做了,你会得到一些不稳定的结果。
不知何故,这让我觉得是错误的。但我不能如实说我已经建模足够多或知道足够多。我只能说我知道的。据我所知,Fact 中的所有值都应该具有相同的粒度。
这两个数字都处于“月份”的相同粒度,但它们不是从它们所代表的角度来看。一个是一个月内的总美元。另一个只是平衡。
这个对吗?我一直在反对这个设计。我这样做有错吗?实际上可以这样做吗?或者我对糟糕设计的“代码气味”感觉是否准确?
任何帮助,将不胜感激。注意:请不要只说“应该是 X 方式”,请解释为什么应该这样,以便我可以从中学习。
编辑:嗯,我了解到我对事实的初步理解是错误的。粒度不是每月一次。粒度是事务级别。所以这意味着在 MONTH_YEAR(即实际上是财务报告期)内将有多个付款和恢复交易。这些将按日期或交易日期发布。但由于业务部门看到的先前报告,以及数据如何存储在遗留系统中,他们希望同时放置交易数据(每行一行)和储备月结余额(每月一行)。
一旦我了解到这一点,我意识到问题不在于添加剂与非添加剂,甚至是半添加剂,因为它是谷物,这是我从一开始就怀疑的。我们的 DBA 团队与项目团队讨论了这个问题,并报告说他们试图将两种不同的颗粒放在同一个事实中,这是不正确的。他们应该将交易提高到每月的水平,然后允许他们获得付款、回收和每月储备余额(即半附加事实),因为一切都将按月进行。或者他们需要找到一种方法将储备余额分解为交易以保留交易级别的粒度。或者他们需要将事实分解为两个事实。一个可以是准备金余额的每月级别。另一个可以在支付和恢复的交易级别。(没有理由他们也不能将付款和追偿放在每月水平的事实中。这取决于业务需求。)
鉴于我所学到的,我会将托马斯的答案标记为正确答案。但是,我觉得我从原始问题开始的讨论仍然值得其他人学习,因此我将保留问题的原始部分。我还打算奖励 nikadam 的回答,因为它教会了我很多关于加法、非加法和半加法事实的知识,并纠正了 我对维度建模的许多误解。
你是对的:“不能在同一个事实表中混合不同的谷物”。
但月末准备金余额和月末支付总额是一码事。它只是事实之一是半加法的。事实类型(加法与否)不定义表的粒度。
根据您的描述,我将您的粒度视为“每月索赔快照”,这使您的事实表成为“定期快照事实表”。
在这篇文章中,Kimball 在同一个事实表中有一个加法和半加法事实的例子。
以下是来自The Data Warehouse Toolkit(第 116 页)的具有半附加事实的定期快照示例:
最佳实践是拥有交易事实表,该表将反映最低原子级别的储备金(付款和调整)的每一次变化。当您处理索赔时,原子级别通常不是索赔而是子索赔(您的保险公司可能有自己的条款)。通常,每个子索赔将代表索赔的不同方以及每一方的付款/准备金。例如,可能不会向被保险人付款,但会向您公司的未投保的受伤人员付款,并向医院和律师付款。
根据您的 BI 工具的性能,您可以直接使用事务事实表来获取每月付款和余额。或者,您可以从每日事务或月底更新定期快照事实表。
处理半加性事实的能力将取决于您使用的 BI 层。有些工具能够轻松处理半加性事实,有些则不能。
Kimball 的主书(The Data Warehouse Toolkit)有一整章(16)关于保险。
你对代码气味的直觉是很好的磨练。
您正在处理的
reserves
是 Kimball 所说的“半加法事实”。它不能很好地汇总到季度或年度。对此的典型解决方案是有两个事实表,一个用于附加事实(
payments
在您的情况下),另一个用于非附加事实。非加法事实实际上并不需要在月级别上有颗粒,您可以将它们一直存储到当天,事情仍然可以正常工作。非加法事实 ,
reserve
的查询方式与其他事实不同。您需要做出一项业务决策:reserve
年度级别意味着什么?是一年中的最后一个月,还是一年中月份的平均值?无论您做出何种选择,您都可以在 Kimball 书籍中关于非加性事实的章节下找到对此建模的解决方案。请注意,如果您使用像 Analysis Services 这样的多维数据集产品,即使您将聚合全部存储在一个表中,聚合也可能“正常工作”。但是,我更喜欢将事物分开,这样关系查询更容易编写(而且事实也更容易加载)。