当我问我们的数据库设计者为什么我们的Fact表没有PK时,我被告知表中没有唯一标识记录的列,即使选择了所有列。当我建议我们在这种情况下成为一个标识栏时,我被告知“我只是在浪费空间而且不需要它。”
我的感觉是源系统中的每个表都应该有一个PK,即使它是一个标识列。鉴于数据仓库(DW)是来自其他系统的数据的接收者 - 如果无法绑定单个记录,我将如何确保DW中的数据准确反映源系统中的数据?如果你有一个失控的加载程序搞砸了数据并运行了一个星期,那么你如何将这些差异与一个没有某种独特约束来比较的实时交易源系统进行协调呢?
答案 0 :(得分:9)
数据仓库不一定是关系数据存储,尽管您可以选择将其设置为一个,因此关系定义不一定适用。
只有当您想要对需要唯一标识符的数据执行某些操作时才需要主键(例如,将其跟踪到源,但这并不总是必需或必要,甚至可能无论如何);数据仓库中的数据通常可以以不需要主键的方式使用。具体而言,您可能不需要区分行。通常用于构建聚合值。
构建数据仓库表时,时间不是必需的维度。
这可能是心理上的不舒服,浪费空间是一个微不足道的问题,但你的同事是正确的 - PK是没有必要的。
答案 1 :(得分:3)
标识类型列是一个“代理”键,用于替换您的“候选”键之一(简单地放置)。如果没有它,则添加代理键列不会添加任何内容。这需要候选人密钥。
答案 2 :(得分:3)
您至少应该在事实表上有一个自然键,这样您就可以识别行并根据需要对其进行协调或跟踪更改。
在SQL Server上,标识列为您提供免费的代理键以及使用序列(例如Oracle)的其他系统,可以相当容易地添加它。代理事实表键可用于各种不同的原因。一些可能的应用是:
有些工具喜欢在事实表上使用数字键,最好是单调增加。一个例子是MS SQL Server Analysis Services,它真的喜欢为用于填充度量值组的事实表提供数字,单调递增的键。增量负载尤其需要这样做。
如果您在事实表之间存在任何关系(例如,熟悉保险的人员的书面获得的保费分类),那么合成密钥在这里很有帮助。
如果您的维度与事实表(例如ICD代码)存在M:M关系,则事实表上的数字键可以简化此操作。
如果您对交易有任何自我加入要求(例如某些交易正在对其他交易进行更正),那么合成密钥将简化这些交易。
如果您在数据仓库中反对重述操作(即通过生成反转并重新声明该行来处理对事务数据的更改),那么您可以为同一个自然键设置多个事实表行。
否则,如果你没有任何东西以1:M关系加入你的事实表,那么合成密钥可能不会被用于任何东西。
答案 3 :(得分:2)
没有主键的数据库表似乎是一个糟糕的设计选择,并为不同类型的异常提供了大量空间,即如何删除或更新此类表中的单个记录?
答案 4 :(得分:2)
你是对的 - 有点儿。没有主键,表不符合关系的最小定义。成为一个不能允许重复行的关系是至关重要的。数据仓库设计中的表应该是关系型的,即使它们不是严格的正常形式。
因此,行中必须有一些列(或列集)用于唯一标识行。但它不一定必须是代理键的标识列。
如果事实表没有可以作为候选键的角色的列集,那么此DW中需要更多的维度表,并且事实表中需要更多列。
这个新的Dimension可能不是主键;它可以与事实表中的现有列组合以创建候选键。
答案 5 :(得分:2)
我同意你的看法。
“有人告诉我,即使选择了所有列,表格中也没有唯一标识记录的列。” - 正如我所理解的那样,这似乎打破了关系数据库的基本功能。
事实包括附加值和维度的外键。对于我所知道的每个维度模型来说,时间是一个明显的维度。如果不出意外,包含时间戳的复合键肯定会足够独特。
我想知道您的DBA是否对维度建模有很多了解。这是一种与正常的关系,交易风格不同的思维方式。
答案 6 :(得分:2)
如果事实表位于星型模式的中心,那么实际上存在候选键。如果将事实表中的所有外键一起使用,则指向维表中的行的那些外键,即候选键。
将它声明为主键可能没什么好处。它唯一能做的就是保护你免受恶意ETL过程的侵害。运行仓库的人可能已经掌握了ETL处理。
就索引和查询速度而言,对于星型模式而言,这与使用面向OLTP的数据库完全不同。经营仓库的人也可以拥有它。
在设计用于OLTP的数据库时,拥有没有主键的表是不明智的。同样的考虑因素不会延续到仓库中。
答案 7 :(得分:2)
我一直认为表应该由最常见的查询或性能命中者排序,因此表的聚簇索引应该与最困难或常见的查询一致。
主键不一定是聚簇索引,所以我知道你可能想知道我在哪里,但我关心的更多是关于聚簇索引而不是主键(说实话,他们通常会遵循每个其他)。
所以对我来说最初的问题不是“我应该在事实表上有代理主键吗?”但更像是“我应该在事实表上有聚集索引吗?”我认为答案是肯定的,你应该有一个(是的,在这个网站上有其他帖子报道这个问题,但我仍然认为这里值得一提,以防这是人们真正问的问题,尽管写错了)
有时你需要一个代理键,但我会衷心地建议代理不是表的聚集索引。这样做会使表格与无意义的代理键一致。 (通常人们会将代理标识列添加到表中,并使其成为主键,默认情况下也是聚集索引)
那么要使用聚簇索引的列是什么?我个人喜欢事实表的日期,为此您可能会添加其他维度的FK以获得唯一性,但这会增加大小并且可能不会提供任何好处,因为索引有用,必须引用相关维度(在密钥生成的重要性顺序。)
为了解决这个问题(以及我在这里回答这个问题的原因)我认为你应该添加一个代理,然后在日期键上创建聚集索引,然后是代理(按此顺序)。我这样做是因为单独的日期不会产生一个独特的行,而是添加代理意志。这样可以按日期排序数据,这有助于所有其他非聚集索引,并使聚簇索引大小保持合理。
此外,随着数据的增长,您可能希望对其进行分区,在这种情况下,您将需要一个始终为日期的分区键。使用日期作为键的主要部分构建聚簇索引可以使这更容易。通过分区,您现在可以使用滑动窗口技术来存档旧数据或加载。
答案 8 :(得分:0)
每行没有唯一标识符甚至比最初看起来更糟糕。当然,这是不稳定的,很容易无意中删除一些行。
但表现也差得多。每当您最终要求数据库为您提供EmployeeType = 'Manager'
的Employees行时,您正在进行字符串比较。标识符更快更好。
此外,存储空间很便宜,在这种情况下,我认为对空间的影响将小于四分之一如果 - 作为数据仓库,您可能正在设计数TB的数据。
答案 9 :(得分:0)
http://www.ralphkimball.com/html/controversies.html
事实表的主键由所有引用的维度外键组成。
事实表通常有10个或更多外键连接到维度表的主键。但是,行唯一性通常只需要事实表的外键引用的子集。大多数事实表都有一个主键,它由外键的连接/复合子集组成。
答案 10 :(得分:0)
使用维度代理键的组合作为事实表的主键在所有情况下都不起作用。考虑存在三个维度a,b和c的情况。在大多数设计中,我们通常有一个“未知”的维度行,假设我总是为此行指定-1的代理键。我可以轻松地在我的事实表中有两行,其中键a = n1,b = n2和c = -1,即重复键,因为这两行没有得到维度c的有效值,因此两者都解析为未知行。
答案 11 :(得分:0)
您在这里混淆了两个问题 - 在事实表中标识唯一记录,并跟踪从源系统到事实表的记录。
在后一种情况下,源系统中的单个记录很可能具有多个事实表记录。想象一下源系统记录,代表从一个帐户到另一个帐户的资金转移。可能有两个事实表记录来表示这一点,一个用于借记帐户,一个用于贷记帐户。此外,可能有多个事实记录表示源系统记录在其生命周期中不同点的不同状态。
对于事实表上的主键问题,确实没有“正确”的答案。您可能需要(例如,单个记录的标识可以在系统用户之间轻松传递,或者单个记录可以轻松删除或更新)。但是对于Oracle系统来说,ROWID可能会很好地做到这一点,只要它偶尔会发生变化并不重要。
实际上,维护单个合成密钥的开销很小,无论如何都可以这么做。您可以选择不对其进行索引,因为索引将是比列本身更大的资源使用者。