【问题标题】:Should one combine foreign keys that point to the same table if all columns are required?如果需要所有列,是否应该组合指向同一个表的外键?
【发布时间】:2018-11-07 20:11:24
【问题描述】:

我经常遇到这种情况。一个例子,

userappId, externalUserId 唯一标识。

xxxContract 有一个外键(fileUploadId, appId, externalUserId) 到表fileUpload,确保文件上传属于指定用户。

xxxContract 有一个外键(businessId, appId, externalUserId) 到表business,确保业务属于指定用户。

以上两项,我们保证用户A的文件上传不会作为用户B业务的合同。


xxxContract 也有一个 fileTypeId 列,即 STORED GENERATED 到某个值,表示“此合同的文件类型为 XXX_CONTRACT

xxxContract 也有一个外键(fileUploadId, fileTypeId) 到表fileUpload

这保证我们只为xxxContract 使用XXX_CONTRACT 文件上传,而不会意外使用其他文件类型。


鉴于上述情况,我们有两个外键指向同一个表fileUpload,甚至有重叠的列,

  • (fileUploadId, appId, externalUserId)
  • (fileUploadId, fileTypeId)

所有的列都是NOT NULL

所以,在我看来,将外键组合成一个更大的外键是安全的,

(fileUploadId, appId, externalUserId, fileTypeId)

而且我们仍将拥有与以前相同的保证。


我的直觉是我不应该组合外键,因为按含义将它们分开并为 FK 提供有意义的名称有助于可维护性。

但我从未接受过有关这些东西的正规教育,所以我想知道行业标准是什么。

相关,将它们组合与分离它们是否有性能优势?

【问题讨论】:

    标签: mysql


    【解决方案1】:

    但我从未接受过有关这些东西的正规教育,所以我想知道行业标准是什么。

    标准是,没有标准。

    正如您已经指出的,您可以使用多个列来定义一个主键。这称为自然主键,例如:用户可以通过名字、姓氏和生日来唯一标识。 (至少几乎永远)

    这种键通常被称为复合键,因为每列单独不起作用,只能将它们组合起来形成主键。

    代理(或人工)主键也是众所周知的:id 列,使用自动增量。

    所以,关于您的问题:是的,如果您有 3 列已经形成自然主键,那么添加更多列是完全安全的。由于已经存在的 3 列将唯一标识行,因此向键添加第 4、第 5 甚至第 6 列没有任何害处。

    您要使用自然主键还是代理主键取决于个人喜好。我从不使用自然键,即使在可能的表上也是如此。

    请记住,每当您需要删除/更新某些内容时,您总是需要知道主键。因此,使用自然键,您需要通过许多方法调用移动多个值,而代理键提供了仅具有“一个”id 来唯一标识行的优势。无需更多信息。

    在性能方面,我假设(基于整数的)代理主键往往比(基于字符串的)自然主键更快。编写查询和/或设计索引时要考虑的列更少。

    【讨论】:

    • 我的问题不在于主键。我的问题是我有两个外键来确保另一个表中的特定行满足某些业务逻辑。但这两个外键可以组合成一个外键而不会失去任何安全性。我应该结合这样的FK吗?或者我应该将它们分开以便维护代码?
    • 为了清楚起见,如果我想确保 fileType 中存在一行,我可以只使用一列的 FK,(fileTypeId)。但我希望这一行也必须属于不同表的同一用户,并且这一行也必须是某种“类型”。所以,我使用的两个 FK 保证了这两个不同的要求。
    猜你喜欢
    • 2013-05-21
    • 1970-01-01
    • 2022-08-18
    • 2015-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-16
    • 2020-09-02
    相关资源
    最近更新 更多