15

我已经阅读了一些似乎使这个问题重复的内容。但通读所有这些让我不确定。我希望根据下面的绝对示例得到答案,因为许多问题/答案在来回辩论中逐渐消失。

如果我有:

dbo.Book
--------
BookID PK int identity(1,1)

dbo.Author
----------
AuthorID PK int identity(1,1)

现在,对于简单的连接表,我有两种选择:

dbo.BookAuthor
--------------
BookID CPK and FK
AuthorID CPK and FK

以上将是两个 FK 上的复合/复合键,以及为两列设置 FK 关系 - 在删除时也使用 Cascade。

或者

dbo.BookAuthor
--------------
RecordID PK int identity(1,1)
BookID FK
AuthorID FK

BookID 和 AuthorID 上的外键关系,以及删除时的 Cascade。还要对 BookID 和 AuthorID 设置唯一约束。

我正在寻找一个简单的答案,说明为什么在上面的特定示例中一种方法比另一种方法更好。我正在阅读的答案非常详细,我正要确定一个复合键,但随后观看了一个视频,该示例使用了我的第一个示例一样的身份列。

似乎这个话题被撕成了两半,但我的直觉告诉我应该只使用复合键。

什么查询效率更高?似乎有一个 PK 标识列以及在两列上设置唯一约束,并且 FK 关系的成本会更高,即使是一点点。

4

6 回答 6

24

这是我在大学时的数据库课程中一直记得的事情。我们涵盖了教科书中关于“实体设计”的部分,它正在谈论连接表......我们称它们为相交表或相交关系。那天我在课堂上其实很专心。教授说,根据他的经验,多对多连接表几乎总是表示一个未识别的缺失实体。这些实体几乎总是以自己的数据结束。

我们得到了一个StudentCourse实体的例子。要让学生参加课程,您需要在这两者之间建立联系。结果,您实际拥有的是一个新实体:一个Enrollment. 在这种情况下,附加数据将是诸如信用类型(审计与常规)或最终等级之类的东西。

直到今天我还记得那个建议……但我并不总是遵循它。在这种情况下,我要做的是停止,并确保就这个问题回到利益相关者那里,并与他们一起处理我们在这个路口可能仍然缺少的数据点。如果我们真的找不到任何东西,那么我将使用复合键。当我们确实找到数据时,我们会想到一个更好的名称,并得到一个代理键。

2020 年更新
我仍然有这本教科书,令人惊讶的是,它和这个问题在几个小时内就引起了我的注意。所以对于好奇的人来说,这是本书第 7 版的第 5 章第 6 节:

https://www.amazon.com/Database-Processing-Fundamentals-Design-Implementation-dp-9332549958/dp/9332549958/

于 2015-03-04T01:13:18.633 回答
8

作为代理键好处的坚定支持者和宣传者,我仍然对全键连接表(例如您的第一个示例)例外。代理键的好处之一是引擎通常针对连接单个整数字段进行优化,这是默认和最常见的情况。

您的第一个提案仍然获得了这个好处,但在每个索引级别上的 fan-put 也增加了 50%,从而减少了连接表上索引的整体大小和高度。尽管对于比大型表更小的任何东西来说,这样做的性能优势可能可以忽略不计,但它是最佳实践并且是免费的。

当我可能会选择其他设计时,如果关系要增加额外的列。那时,它不再是严格意义上的连接表。

于 2015-03-04T00:45:18.117 回答
7

我更喜欢第一种设计,使用复合键。即使父表有它们,在联结表上有一个标识列也不会给您带来优势。您不会BookAuthor使用标识列查询,而是使用BookIDand查询它AuthorID

此外,添加标识将允许重复组合,除非您设置约束BookIDAuthorID

此外,如果您的主键是(BookID, AuthorID),则需要在 上建立索引AuthorID, BookID)。如果您想查询作者所写的书籍,这将有所帮助。

于 2015-03-04T00:17:27.187 回答
5

使用复合键也是我的选择。原因如下:

更少的存储开销

假设您将使用代理键。由于您可能想要查询所有作者的特定书籍,反之亦然,您需要以 BookId 和 AuthorId 开头的索引。出于性能原因,您应该在两个索引中都包含另一列,以防止聚集键查找。您可能希望将其中一个设为唯一,以确保不会将重复的 BookId/AuthorId 组合添加到表中。

因此,最终结果是:

  • 数据存储3次而不是2次
  • 要验证 2 个唯一约束而不是 1 个

查询联结表引用表

即使您要添加一个表,例如Contributions (AuthorId, BookId, ...)引用联结表。大多数查询根本不需要接触联结表。例如:查找特定作者的所有贡献只涉及作者和贡献表。

于 2015-03-04T12:53:29.757 回答
4

根据联结表中的数据量,复合键最终可能会导致性能低于自动生成的顺序主键。

主键是表的聚集索引,这意味着它决定了行在磁盘上的存储顺序。如果主键的值不是按顺序生成的(例如,它是由表中的外键组成的组合键,其中行的顺序与联结表的行的顺序不同,或者它是 GUID 或其他随机键),那么每次将一行添加到联结表中,需要对联结表的行进行重新洗牌。

于 2020-02-18T14:42:31.790 回答
1

您可能应该使用复合/复合键。这样你就可以完全建立关系——一个作者可以写很多本书,而一本书可以有多个作者。

于 2015-03-04T00:47:16.973 回答