在啥情况下我们需要在数据库中使用组合键
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_id
和book_id
的votes
表上的复合主键与(person_id, book_id)
的组合具有生成的ID 和唯一索引一样有意义,如果不是更多的话。人和书的结合定义投票记录。
【讨论】:
【参考方案2】:不应在“新”应用程序中考虑复合键。它们过去曾被那些认为“业务密钥”比“代理密钥”更好的人使用。
编辑:正如克里斯所问,我正在扩展我的答案。
首先让我说明我将这个问题理解为“复合主键”与“代理键”。
另外,我承认有一个用例使复合键有意义:在交叉引用表中,也称为“链接表”。它们在多对多表中使用,并且仅包含两个字段,两个字段都构成外部参照表的主键。例如,UserRole
表将包含user_id
和role_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_id
和 book_id
上拥有一个复合/代理键,这将非常有用,但您也可以拥有一个 CAN 作为主要的 id 列关键也是,但它不一定是。您可以使用 person_id
和 book_id
作为 PK 或只是一个索引,对于 id 列也是如此。 id
列使您在删除内容或选择单个列以进行查看时更轻松。对于今天的 RDBMS,您通常不必担心表大小,建议包含单个列 - 最好为所有表自动增加标识列,以防万一。我相信它不会以任何方式伤害您。
【讨论】:
以上是关于在啥情况下我们需要在数据库中使用组合键的主要内容,如果未能解决你的问题,请参考以下文章
在啥情况下我们必须使用 localstorage 而不是 cookie? [复制]