4

当我问我们的数据库设计人员为什么我们的 Fact 表没有 PK 时,我被告知即使选择了所有列,表中也没有一组列可以唯一标识一条记录。当我建议我们在这种情况下创建一个身份列时,我被告知“我只是在浪费空间而且不需要它。”

我的感觉是,源系统中的每个表都应该有一个PK,即使它是一个标识列。鉴于数据仓库 (DW) 是来自其他系统的数据的接收者,如果无法绑定各个记录,我将如何确保 DW 中的数据准确反映源系统中的内容?如果你有一个失控的加载程序,它搞砸了数据并且已经运行了一周,你将如何在没有某种独特约束来比较的实时事务源系统中调和这些差异?

4

12 回答 12

8

数据仓库不一定是关系数据存储,尽管您可以选择使其成为一个,因此关系定义不一定适用。

仅当您想对需要唯一标识符的数据执行某些操作时才需要主键(例如将其跟踪到源,但这并不总是必需或必要甚至可能的);并且数据仓库中的数据通常可以以不需要主键的方式使用。具体来说,您可能不需要将行彼此区分开来。最常用于构造聚合值。

时间不是构建数据仓库表的必要维度。

这可能在心理上不舒服,浪费空间是一个小问题,但你的同事是正确的——PK 不是必需的。

于 2009-05-30T18:33:09.677 回答
4

身份类型列是替换您的“候选”键之一的“代理”键(简单地说)。如果您无法识别没有它的行,则添加代理键列不会增加任何内容。这需要一个候选键。

于 2009-05-30T18:23:09.240 回答
3

您至少应该在事实表上有一个自然键,以便您可以识别行并将它们与源相协调,或在必要时跟踪更改。

在 SQL Server 上,标识列免费为您提供代理键,而在使用序列的其他系统(例如 Oracle)上,可以相当容易地添加它。由于各种不同的原因,代理事实表键可能很有用。一些可能的应用是:

  • 有些工具喜欢在事实表上使用数字键,最好是单调递增的。这方面的一个例子是 MS SQL Server 分析服务,它非常喜欢为用于填充度量组的事实表提供一个数字的、单调递增的键。这对于增量负载尤其需要。

  • 如果事实表之间有任何关系(例如熟悉保险的人的书面收入明细),那么合成键在这里很有帮助。

  • 如果您的维度与事实表存在 M:M 关系(例如 ICD 代码),那么事实表上的数字键可以简化此操作。

  • 如果您对交易有任何自加入要求(例如,某些交易是对其他交易的更正),那么合成密钥将简化这些交易。

  • 如果你在你的数据仓库中做相反的重述操作(即通过生成反转和重新陈述行来处理对事务数据的更改),那么你可以为同一个自然键拥有多个事实表行。

否则,如果您没有任何东西以 1:M 关系加入事实表,那么合成密钥可能不会用于任何事情。

于 2013-02-22T17:01:13.160 回答
2

没有主键的数据库表似乎是一个糟糕的设计选择,并且为不同类型的异常留出了很多空间,即您将如何删除或更新此类表中的单个记录?

于 2009-05-30T18:16:47.253 回答
2

你是对的——在某种程度上。没有主键,表不符合关系的最低定义。作为关系的基础,它不能允许重复的行。数据仓库设计中的表应该是关系型的,即使它们不是严格的标准形式。

因此,行中必须有一些列(或一组列)用于唯一标识行。但它不一定是代理键的标识列。

如果 Fact Table 没有一组列可以充当候选键的角色,那么这个 DW 中需要更多的 Dimension Table,并且 Fact Table 中需要更多的列。

这个新的 Dimension 本身可能不是主键;它可以与事实表中的现有列组合以创建候选键。

于 2009-05-30T18:18:36.173 回答
2

我会同意你的。

“有人告诉我,表中没有一组列可以唯一标识一条记录,即使选择了所有列。” - 据我了解,这似乎打破了关系数据库的一些基本内容。

事实由附加值加上维度的外键组成。时间是我所知道的每个维度模型所共有的一个明显维度。如果不出意外,包含时间戳的复合键肯定足够唯一。

我想知道您的 DBA 是否对维度建模有很多了解。这是一种不同于正常关系型、交易型的思维方式。

于 2009-05-30T18:22:09.850 回答
2

如果事实表位于星型模式的中心,则实际上存在候选键。如果将事实表中的所有外键放在一起,即指向维度表中行的外键,那就是候选键。

将其声明为主键可能没有多大用处。它唯一能做的就是保护您免受流氓 ETL 过程的侵害。运行仓库的人可能会很好地处理 ETL。

就索引和查询速度而言,星型模式与面向 OLTP 的数据库完全不同。经营仓库的人可能也有这个。

在为 OLTP 设计数据库时,让表没有主键是不明智的。相同的考虑不会延续到仓库中。

于 2009-05-31T02:30:07.967 回答
2

我一直认为一个表应该按照最常见的查询或性能命中者排序,因此表的聚集索引应该与最困难或最常见的查询一致。

主键不必是聚集索引,所以我知道您可能想知道我将如何处理,但我更关心的是聚集索引而不是主键(老实说,它们通常相互跟随)。

所以对我来说最初的问题不是“我应该在事实表上有一个代理主键吗?” 但更像是“我应该在事实表上有一个聚集索引吗?” 我认为答案是肯定的,你应该有一个(是的,这个网站上还有其他帖子涵盖了这个问题,但我仍然认为在这里值得一提,以防这是人们真正提出的问题,尽管措辞错误)

有时您需要代理键,但我衷心建议代理键不是表的聚集索引。这样做会按照无意义的代理键对表进行排序。(通常人们在表中添加一个代理标识列,并使其成为主键,默认情况下也是聚集索引)

那么在哪些列上创建聚集索引?我个人喜欢事实表的日期,为此您可能会添加一些其他维度的 FK 以获得唯一性,但这会增加大小并且可能不会提供任何好处,因为为了使索引有用,必须引用相关维度(在生成密钥的重要性顺序)。

为了解决这个问题(以及我在这里回答这个问题的原因),我认为您应该添加一个代理项,然后在日期键上创建聚集索引,然后是代理项(按此顺序)。我这样做是因为单独的日期不会成为唯一的行,而是添加代理将。这使数据按日期排序,这有助于所有其他非聚集索引,并保持聚集索引大小合理。

此外,随着数据的增长,您可能希望对其进行分区,在这种情况下,您将需要一个分区键,该分区键始终是日期。以日期作为键的主要部分构建聚集索引使这更容易。通过分区,您现在可以使用滑动窗口技术来归档旧数据或加载。

于 2012-02-15T13:53:59.043 回答
0

没有每行的唯一标识符比最初看起来更糟糕。当然,这是不稳定的,很容易无意中删除一些行。

但是性能也差很多。每次您最终要求数据库为您获取员工的行时,EmployeeType = 'Manager'您都在进行字符串比较。标识符更快更好。

此外,存储很便宜,在这种情况下,我想如果那样的话,对空间的影响将不到四分之一个百分点——作为数据仓库,您可能正在为 TB 级数据设计。

于 2009-05-30T21:49:19.577 回答
0

http://www.ralphkimball.com/html/controversies.html

寓言:

事实表的主键由所有引用的维度外键组成。

事实:

事实表通常有 10 个或更多外键连接到维度表的主键。然而,行唯一性通常只需要事实表的外键引用的一个子集。大多数事实表都有一个主键,它由外键的连接/复合子集组成。

于 2009-06-03T08:54:24.463 回答
0

使用维度代理键的组合作为事实表的主键并不适用于所有情况。考虑存在三个维度a、b和c的情况。在大多数设计中,我们通常有一个“未知”的维度行,假设我总是为这一行分配 -1 的代理键。我可以很容易地在我的事实表中有两行具有键 a=n1、b=n2 和 c=-1,即重复键,因为这两行没有得到维度 c 的有效值,因此都解析为未知行。

于 2012-12-19T22:37:40.007 回答
0

您在这里混淆了两个问题——识别事实表中的唯一记录,以及从源系统到事实表的跟踪记录。

在后一种情况下,源系统中的单个记录很可能具有多个事实表记录。想象一个源系统记录,它表示资金从一个帐户转移到另一个帐户。可能有两条事实表记录来表示这一点,一条用于借方账户,一条用于贷方账户。此外,可能有多个事实记录来表示源系统记录在其生命周期的不同点的不同状态。

对于事实表的主键问题,真的没有一个“正确”的答案。您可能需要一些理想/基本特征(例如,单个记录的身份可以在系统用户之间轻松通信,或者单个记录可以轻松删除或更新)。但是,对于 Oracle 系统,ROWID 可能会很好地做到这一点,只要它是否偶尔更改无关紧要。

但实际上,维护单个合成密钥的开销很小,无论如何您都可以这样做。您可能会选择不为其编制索引,因为索引将比列本身消耗更多的资源。

于 2013-03-10T11:08:33.103 回答