复合主键:好还是坏?

新手上路,请多包涵

虽然可以使用复合主键,但对于下面的情况,这真的是一种不好的做法吗? Stackoveflow 上的共识 _似乎在这个问题上是双向的_。

为什么?


我想将订单的付款存储在单独的表中。原因是,一个订单可以有许多项目,这些项目以多对多关系的形式在单独的表中处理。现在,如果我的付款表不使用复合主键,我将失去我唯一的 PaymentID

 [PaymentId] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
[OrderId] INT NOT NULL PRIMARY KEY --Also a Foreign Key--

现在,如果我只是删除 OrderId 的主键,我将在这里失去一对一的关系,所以 Many OrderIds can be associated to many PaymentIds ,我不想要这个。

这似乎就是为什么其他关于 SO 的答案(大部分)得出的结论是复合键是一个坏主意。如果不好,那么最佳做法是什么?

原文由 JAX 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 817
2 个回答

没有结论说复合主键不好。

最佳做法是让 一些 列或多列唯一地标识一行。但在某些表中,单列本身不足以唯一标识一行。

SQL(和关系模型)允许复合主键。在某些情况下,这是一个很好的做法。或者,另一种看待它的方式是,在所有情况下这都不是坏习惯。

有些人认为 每个 表都应该有一个整数列,它会自动生成唯一值,并且应该作为主键。有些人还声称这个主键列应该总是被称为 id 。但这些都是 _惯例_,不一定是最佳实践。约定有一些好处,因为它简化了某些决定。但是约定也是有限制的。

您的订单可能需要多次付款,因为有些人 在layaway上 购买,或者他们有多种付款来源(例如两张信用卡),或者两个不同的人想为订单的一部分付款(我经常去和朋友一起去餐厅,我们每个人都自己付饭钱,所以工作人员处理了我们每张信用卡上一半的订单)。

我将设计您描述的系统如下:

 Products  : product_id (PK)

Orders    : order_id (PK)

LineItems : product_id is (FK) to Products
            order_id is (FK) to Orders
            (product_id, order_id) is (PK)

Payments  : order_id (FK)
            payment_id - ordinal for each order_id
            (order_id, payment_id) is (PK)

这也与 识别关系 的概念有关。如果定义仅因为订单存在而存在付款,则将订单作为主键的一部分。

请注意,LineItems 表也缺少自己的自动增量单列主键。多对多表是一个很好地使用复合主键的经典示例。

原文由 Bill Karwin 发布,翻译遵循 CC BY-SA 3.0 许可协议

从内部数据库引擎的角度来看,使用复杂的主键没有障碍。索引可以正常工作,完整性约束可以正常工作,没有性能缺陷等。

理论上 它们很好,但在 实践 中应该考虑一些事情(可能的问题):

  1. 相关表中的外键(FK)必须有多个列作为 PK。如果有简单的 PK,关系一致性将更容易维护。

  2. 在(网络)应用程序中,客户多次需要选择/获取一些数据(从数据库表中检索)。每条记录的背后总是PK,导致一些动作。如果将这些记录表示为 Web 链接,则更易于维护为具有多个 URL 参数的链接。但是,如果要从下拉列表中选择数据,那么由于 HTML 表单下拉列表通常只使用一个关键参数,因此为 PK 实现更多参数的传输可能具有挑战性。

通常,当您处理复杂的 PK(多列)时,您的代码应该为这些列(getter/setter)、应用程序中的参数传输、入侵检查等相乘。最后,在应用程序开发过程中,您得出的结论是,可能更容易拥有简单PK 虽然在 DB 建模期间这不是问题。

原文由 sbrbot 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进