【问题标题】:Is there any drawback when tying a foreign key to a non-primary key?将外键绑定到非主键有什么缺点吗?
【发布时间】:2016-02-01 19:37:52
【问题描述】:

假设我们有一个这样的工作表:

  • 工作(ID、编号);

假设我们有一个跟踪工作时间的客户请求,我们创建了一个表格,如下所示:

  • (A) job_timer(id、job_id、时间戳);

但我们可以选择如何将其绑定到job 表,因此我们也可以:

  • (B) job_timer(id、job_number、timestamp);

假设 job_number 是UNIQUE

我习惯于根据 id 创建外键,所以 A) job_id 将是我所看到的方式。但是,客户正在按工作编号查找工作,如果我直接通过 B)job_number 进行查找,它将为我和数据库节省一些工作。但我应该这样做吗?

使用job_id 时需要做更多工作,即给定工作编号,我只需要使用job_timer 表。当给定job_id 时,我需要绑定两个表——更多的认知编程工作,更多的数据库工作。

请注意,类似的问题 Foreign Key to non-primary key 解决了非主键的唯一性,但我不认为它解决了我的问题。

原始表 (job) 是遗留代码库的一部分,其中 idnumber 两个字段在整个代码中都被广泛使用,从这个意义上说,我有一个“拆分主键”条件。由于缺乏完整的测试覆盖率,将其剔除将是令人望而却步的。为什么创建 number 字段以及为什么将其设为 varchar 都是很好的问题。我敢肯定在某个时候一定是有原因的。

我正在寻找类似“是的,继续,这完全没问题,在这种情况下没有最佳实践”或“不,如果你这样做,你可能会遇到问题 X , Y, Z 未来”。

【问题讨论】:

  • d'oh,对...多个匹配的父 ID 会模棱两可...我可能应该去睡觉了。
  • 如果job 表中的number 是唯一的,那么您应该将that 设为主键并完全删除id 列(因为它显然不会给表格增加任何价值)。这意味着工作编号也永远不会改变。
  • @horse: 好抓! id 字段是多余的...
  • 还想补充一点,就我而言...原始表 (job) 是遗留代码库的一部分,其中 idnumber 两个字段都在整个代码中广泛使用,并且从这个意义上说,我有一个“拆分主键”条件。由于缺乏完整的测试覆盖率,将其剔除将是令人望而却步的。为什么创建 number 字段以及为什么将其设置为 varchar 是很好的问题。我相信在某些时候一定是有原因的。

标签: sql database database-design foreign-keys


【解决方案1】:

TL;DR 当列列表的值必须作为另一个PRIMARY KEY 或@ 列表的值出现时,始终声明FOREIGN KEY 约束(链) 987654324@ 列。但是当有多个 CK 时,选择哪个 CK(候选键)作为 FK(外键)引用最终是实用的。这些标准基本上是用于选择 PK(主键)的标准,因为将 CK 区分为 PK 最终是为了在 FK 中首选使用。一个典型的列表是familiarity, irreducibility, stability & simplicity。这里过去的使用表明任何一个 CK 都是合理的。尽管考虑number 仅用于最终输出解释了它的varcharness 和它的独特性,尽管id 的存在和独特性。如果您曾经同时包含两者,请注意在这对上声明 FOREIGN KEY 可能是合适的。 (需要在job 的对上添加UNIQUE NOT NULL。)


超级键是一组唯一的非空列。 CK 是一个不包含更小的超级密钥的超级密钥。一个表可以有任意数量的 CK。 PK 是一个杰出的 CK。

当表中子行的值也是引用表中某些超键子行的值时,我们可以说“外来超键”成立。如果超键是 CK,那么外部超键是 FK。我们将 CK 和外部超键告诉 DBMS,这样它就可以防止无效的数据库状态。

SQL UNIQUE NOT NULL 实际上声明了一个超级键。所以 SQL PRIMARY KEY 实际上声明了一个可区分的超键。如果超级键是 CK,则它是 PK。 SQL FOREIGN KEY 实际上声明了一个外部超键。如果引用的超键是 CK,则它是 FK。

您的“split PK”表只是一张有两个 CK 的表。 (这形成了一个超键,因为 CK 的所有超集都是超键。)就约束声明而言,首要性无关紧要。您应该只声​​明保持的约束,以便 DBMS 可以强制执行它们。

请注意,如果您有一个带有id number 作为FK 的表,那么很可能 值必须出现在job 中。如果是这样,则通过FOREIGN KEY 将该对声明为外部超级键。当存在自然键时,需要添加外部超级键是具有代理键的缺点。另一方面,只要有多个 CK,就会出现这种情况。

PS 唯一列集的任何超集都是唯一的。但是 SQL 要求您将 FK 的目标声明为 UNIQUE NOT NULL,即使它必须通过包含一些声明为唯一的较小集而已经是唯一的。因此,当有一个 id-number 对必须出现在 job 中时,您应该声明复合 FK 和复合超级键。 PPS 所有这些声明的重点是完整性,而不是索引 用于优化。 (虽然这也很重要。)

【讨论】:

  • 谢谢。关于在 pair 上声明 UNIQUE 的问题。如果我执行 UNIQUE(id, number) 然后我只查找 number ,则索引不会以某种方式工作,索引将不会被使用?我的印象是,只有在查找id 或同时查找idnumber 时才使用这样的索引。但是当仅查找number 时,该索引未使用。我看不出在 pair 上声明 UNIQUE 比在 id 上分别声明 UNIQUE 和在 number 上分别声明 UNIQUE 更好。当前代码仅对 id 或 number 进行大量查找,但不能同时对两者进行查找。您对未来有何建议?
  • 你是对的,它对于唯一性是多余的,对于索引是不必要的。但是 SQL 只要求将每个 FK 目标列集声明为 UNIQUE NOT NULL。请参阅我的答案的新最后一段。另请参阅我编辑的第一句话。
  • 我相信许多 SQL 实现会自动为主键创建索引,但不一定为主键创建索引,即使它们被某些 FK 引用也不一定。所以可能有 FK 引用的 CK 没有可用的索引,这会在某些时候损害性能。 (这里的关键是“缺点”是由于没有索引,而不是因为引用的键是“次要的”。)
猜你喜欢
  • 2022-06-14
  • 2013-05-12
  • 2013-08-28
  • 1970-01-01
  • 2016-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多