在啥情况下我们需要在数据库中使用组合键

Posted

技术标签:

【中文标题】在啥情况下我们需要在数据库中使用组合键【英文标题】:Under what condition we need to use composite keys in database在什么情况下我们需要在数据库中使用组合键 【发布时间】:2011-07-12 17:56:52 【问题描述】:

我已经看到我们可以使用组合键,其中主键由两个表的组合主键组成。

喜欢人和书

person_id and book_id will make the primary key.

但我想问一下,我们需要对编程语言进行硬编码

我的意思是,我可以使用任何名称的单独列作为主键 然后我不必硬编码它,我可以像往常一样执行我的功能

id,person_id ,book_id

【问题讨论】:

【参考方案1】:

如果您要存储人与书之间的一对一关系(例如,您正在运行一个网站,用户可以在该网站上以 1-5 的等级对他们阅读过的书进行评分),那么person_idbook_idvotes 表上的复合主键与(person_id, book_id) 的组合具有生成的ID 和唯一索引一样有意义,如果不是更多的话。人和书的结合定义投票记录。

【讨论】:

【参考方案2】:

不应在“新”应用程序中考虑复合键。它们过去曾被那些认为“业务密钥”比“代理密钥”更好的人使用。

编辑:正如克里斯所问,我正在扩展我的答案。

首先让我说明我将这个问题理解为“复合主键”与“代理键”。

另外,我承认有一个用例使复合键有意义:在交叉引用表中,也称为“链接表”。它们在多对多表中使用,并且仅包含两个字段,两个字段都构成外部参照表的主键。例如,UserRole 表将包含user_idrole_id,仅此而已。例如,对于这样的表,Java 中没有类表示。这通常是一个@ManyToMany,两边都有一个Collection

我在另一个答案 (Hibernate : Opinions in Composite PK vs Surrogate PK) 中分享了我对自然键与代理键的看法,我相信复合键具有自然键的一些缺点,但没有带来任何真正的好处。

复合键的问题是您需要两个 值来唯一标识一条记录。一旦您开始拥有引用第一个表中记录的表,这就会成为一个问题。然后第二个表需要 两个 列才能引用 一个 记录。如果第二个表使用由单个值 + 外键组成的复合键,那么您现在有 三个 列来唯一标识 一个 记录。第三个表需要这些 三个 额外的列来引用第二个表中的 一个 记录。真的,这是一个雪球。

另一个缺点是需求确实会改变。每时每刻。所以,今天看起来不错的组合键,明天就根本不是键了。这就是我们有代理键的原因:面向未来。

复合键主要用于使表中的记录基于一组列是唯一的。例如,如果您有一个 Customers 表,您可能有一个 NationalId+Country 作为唯一值,这意味着如果他们的国家/地区是美国,两个用户不能共享同一个 SSN。但是,如果两条记录不在同一个国家/地区,则它们可能具有相同的编号。如果您喜欢复合键,这将是一个不错的选择。但正如我之前暗示的,您可以使用代理键并应用unique 约束。您将获得复合键的好处以及代理键的安全性。

【讨论】:

请详细说明原因。另外,请参阅 symcbean 并做出响应。 我刚刚扩展了我的答案。它比我想要的要大,但我希望这个解释就足够了:-) 根据您的论点,即使是多对多链接表也应该有一个代理 PK 以备将来验证。例如。以后可能需要在单独的表格中添加引用这些链接的信息。 是的。实际上,我总是这样做。但在这种情况下,如果你不这样做,我可以原谅你:)【参考方案3】:

代理键本质上是不好的,应该不惜一切代价避免。它们在现实世界中毫无意义。但有时它们是必要的。

暂且不说,您的示例确切地说明了为什么需要复合键 - 不止一个人可以拥有一本特定书籍的副本 - 一个人可以拥有不止一本书 - 这是 N:M 关系。在关系数据库中表示这一点很简单:你在中间放另一个表,上面有书的 PK 和人的 PK。

id,person_id ,book_id

但是(除非您想满足需要区分同一人拥有的同一本书的 2 个副本的情况,在这种情况下,架构需要进行其他一些更改)因为 person_id 和 book_id 的组合已经是唯一的,为什么您需要另一个与您尝试建模的数据无关的唯一标识符。

【讨论】:

请详细说明您的第一段 - 为什么?另外,请参阅partenon的回答并做出回应。 假设您将它用于book_loan 表,并且一个人只能拥有一本书的副本。然后稍后该要求发生变化。使用代理键,您只需要删除一个约束,但复合键将不再是唯一的,您需要创建一个新的唯一键 - 更痛苦。 @z7sg: 如果你不把书借给红头发的人,并且只在一个月内借出带有 R 的科幻小说,你也需要进行其他架构更改 @chris:分离、糟糕的查询设计、糟糕的性能、隐藏的依赖关系、序列预测带来的安全问题、认知负荷......【参考方案4】:

我想不出您需要使用复合键的任何条件。 Pro 使用单个 id 列的一些参数包括: 1. 更好的索引 2. 更简单的连接 3. 更易于设计 gui 4. 大多数 ORM 在单字段 PK 上工作得更好(不幸的是) 5. 更容易删除记录

在您的情况下,尽管您可以在 person_idbook_id 上拥有一个复合/代理键,这将非常有用,但您也可以拥有一个 CAN 作为主要的 id 列关键也是,但它不一定是。您可以使用 person_idbook_id 作为 PK 或只是一个索引,对于 id 列也是如此。 id 列使您在删除内容或选择单个列以进行查看时更轻松。对于今天的 RDBMS,您通常不必担心表大小,建议包含单个列 - 最好为所有表自动增加标识列,以防万一。我相信它不会以任何方式伤害您。

【讨论】:

以上是关于在啥情况下我们需要在数据库中使用组合键的主要内容,如果未能解决你的问题,请参考以下文章

在啥情况下我们必须使用 localstorage 而不是 cookie? [复制]

SQLserver数据库中,在啥情况下删除数据不能成功?

在啥情况下我们需要在javascript中实现单例类[重复]

er.字母组合发音,在啥情况下发啥音?

在啥情况下我应该使用尝试而不是二叉树/哈希表? [复制]

java中几种Map在啥情况下使用,并简单介绍原因及原理