19

我正在设计一个供 Web 应用程序使用的小型 SQL 数据库。

假设一个特定的表有一个名称字段,不允许任何两行具有相同的值。但是,用户将能够随时更改名称字段。

此表中的主键将用作其他表中的外键。因此,如果将 Name 字段用作主键,则任何更改都需要传播到其他表。另一方面,唯一性要求将被自动处理。

我的直觉是添加一个整数字段作为主键,它可以由数据库自动填充。拥有这个领域有什么意义还是浪费时间?

4

11 回答 11

25

出于您提到的原因,我自己会使用生成的 PK。此外,按整数索引和比较比按字符串比较快。您也可以在名称字段上放置唯一索引,而无需将其设为主键。

于 2008-10-03T13:10:29.700 回答
12

您所描述的称为代理键。详细答案请参见Wikipedia 文章

于 2008-10-03T13:23:28.300 回答
6

尽管在整数列上搜索和加入会更快(正如许多人所指出的那样),但从一开始就不加入会更快。通过存储自然键,您通常可以消除连接的需要。

对于小型数据库,对外键引用的 CASCADE 更新不会对性能产生太大影响,除非它们非常频繁地更改。

话虽如此,在这种情况下,您可能应该使用整数或 GUID 作为代理键。可按设计更新的主键不是最好的主意,除非您的应用程序有非常令人信服的商业理由要求名称唯一,否则您将不可避免地发生冲突。

于 2008-10-03T13:33:33.367 回答
2

是的 - 根据经验,每张桌子总是如此。

您绝对不应该将可更改字段用作主键,并且在绝大多数情况下,您不希望将具有任何其他用途的字段用作主键。

这是 db 模式的基本良好实践。

于 2008-10-03T13:17:24.223 回答
2

从性能的角度来看,拥有一个整数主键总是一件好事。使用整数主键,您的所有关系都会更有效率。例如,JOIN 会更快(SQL Server)。

它还将允许您将来修改数据库。很多时候,您有一个唯一的名称列,但后来发现它根本不是唯一的名称。

现在,您也可以通过在其上设置索引来强制列Name的唯一性。

于 2008-10-03T13:17:51.057 回答
2

我会使用自动生成的 ID 字段作为主键。基于整数 ID 的表比文本更容易连接。此外,如果字段Name经常更新,如果它是主键,数据库将面临更频繁地更新该字段索引的压力。

如果字段名称始终是唯一的,您仍应在数据库中将其标记为唯一。但是,通常会有两个相同名称的可能性(在您的情况下可能不是现在,但可能在将来),所以我不推荐它。

使用 ID 的另一个优点是如果您需要对数据库进行报告。如果您有一个针对给定名称集的报告,即使名称可能发生变化,报告上的 ID 过滤器也会保持一致。

于 2008-10-03T13:22:04.607 回答
1

如果你生活在理论数学家的稀有圈子里(就像 C.Date 一样,因为所有数据值都是已知且正确的),那么主键可以从识别您所指的理想化柏拉图实体的数据组件(即姓名+生日+出生地点+父母的姓名),但在混乱的现实世界中可以识别您的现实世界实体的“合成密钥”数据库的上下文是一种更实用的做事方式。(并且可以为空的字段可能非常有用。拿那个吧,关系设计理论的人!)

于 2008-10-03T13:31:11.607 回答
1

记录的主键必须是唯一且永久的。如果一个记录自然有一个满足这两个条件的简单键,那么就使用它。但是,它们并不经常出现。对于人员记录,此人的姓名既不是唯一的也不是永久的,因此您几乎必须使用自动增量。

自然键起作用的一个地方是代码表,例如,将状态值映射到其描述的表。给“Active”一个主键 1,给“Delay”一个主键 2 等没有什么意义。当给“Active”一个主键“ACT”一样容易时;“延迟”、“DLY”;“等待”、“HLD”等。

另请注意,有人说您应该在字符串上使用整数,因为它们比较快。不是真的。比较两个 4 字节字符字段的时间与比较两个 4 字节整数字段的时间完全相同。更长的字符串当然会花费更长的时间,但是如果您保持代码简短,则没有区别。

于 2008-10-03T13:31:31.403 回答
1

如果您的 name 列将发生变化,那么它并不是一个很好的主键候选者。主键应定义表的唯一行。如果它可以改变它并没有真正做到这一点。在不了解您的系统的更多细节的情况下,我不能说,但这可能是使用代理键的好时机。

我还将添加它以消除对所有主键使用自动递增整数的神话。使用它们并不总是能提高性能。事实上,很多时候情况恰恰相反。如果您有一个自动递增的列,这意味着系统中的每个 INSERT 现在都有生成新值的额外开销。

此外,正如 Mark 指出的那样,如果您有一系列相关的表,则在所有表上都有代理 ID,要从一个表到另一个表,您可能必须将所有这些表连接在一起以遍历它们。使用自然主键通常不是这种情况。用整数连接 6 个表通常比用字符串连接 2 个表要慢。

当您在所有表上都有自动递增的 ID 时,您也经常失去执行基于集合的操作的能力。您现在必须在游标或其他循环中一次插入一个父行,而不是在父表中插入 1000 行,然后在子表中插入 5000 行,以便获取生成的 ID,以便您可以分配它们给相关的孩子。我已经看到一个 30 秒的过程变成了一个 20 分钟的过程,因为有人坚持在数据库中的所有表上使用自动递增的 ID。

最后(至少出于我在这里列出的原因 - 当然还有其他原因),在所有表上使用自动递增 ID 会导致设计不佳。当设计人员不再需要考虑表的自然键可能是什么时,通常会导致错误的重复数据最终出现在数据中。您可以尝试避免唯一索引的问题,但根据我的经验,开发人员和设计人员不会付出额外的努力,并且在使用他们的新系统一年后,他们发现数据是一团糟,因为数据库没有通过自然键对数据进行适当的约束。

使用代理键当然是有时间的,但在所有表上盲目地使用它们几乎总是一个错误。

于 2008-10-03T14:07:32.080 回答
0

每一行的主键必须是唯一的。auto_increment Integer 是一个非常好的主意,如果您对填充主键没有其他想法,那么这是最好的方法。

于 2008-10-03T13:16:12.073 回答
0

除了所说的,考虑使用 UUID 作为 PK。它将允许您创建跨多个数据库的唯一键。

如果您需要将数据与其他数据库导出/合并,那么数据将始终保持唯一,并且可以轻松维护关系。

于 2016-03-01T10:48:27.170 回答