数据库设计-我应该有一个专用的主键字段吗



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

假设一个特定的表有一个Name字段,不允许两行具有相同的值。但是,用户可以随时更改"名称"字段。

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

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

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

您所描述的被称为代理密钥。详细答案请参阅维基百科文章。

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

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

也就是说,在这种情况下,您可能应该使用整数或GUID作为代理密钥。一个可按设计更新的主键并不是最好的主意,除非你的应用程序有一个非常有说服力的商业理由使其名称唯一,否则你将不可避免地发生冲突。

是-根据经验,始终适用于每个表。

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

这是数据库模式的基本良好实践。

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

它还将允许您将来修改数据库。通常情况下,您有一个唯一的名称列,但后来发现该名称根本不是唯一的。

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

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

如果字段Name始终是唯一的,则仍应在数据库中将其标记为唯一。然而,通常会有两个相同名字的可能性(可能不是现在,但可能在未来,在你的情况下),所以我不建议这样做。

使用ID的另一个优点是在数据库中有报告需求的情况下。如果您有一个针对给定名称集的报表,则即使名称可能发生更改,报表上的ID过滤器也会保持一致。

如果你生活在理论数学家的精英圈子里(就像C.Date在没有null的地方一样,因为所有的数据值都是已知和正确的),那么主键可以从数据的组成部分中构建,这些组成部分可以识别你所指的理想化柏拉图实体(即姓名+生日+出生地+父母姓名),但在混乱的现实世界中,可以在数据库上下文中识别真实世界实体的"合成密钥"是一种更实用的方法。(可以为null的字段对非常有用。就拿这个来说,关系设计理论的人!)

如果您的名称列将发生更改,那么它实际上不是主键的好候选者。主键应该定义表中唯一的一行。如果它可以改变,那就不是真的这么做了。如果不了解有关您的系统的更多细节,我不能说,但现在可能是代理密钥的好时机。

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

此外,正如Mark所指出的,对于所有表上的代理ID,如果你有一个相关的表链,为了从一个表到另一个表,你可能必须将所有这些表连接在一起才能遍历它们。对于自然主键,通常情况并非如此。用整数连接6个表通常比用字符串连接2个表慢。

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

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

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

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

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

另外请注意,有些人说应该使用整数而不是字符串,因为它们比较起来更快。不是真的。比较两个4字节字符字段的时间与比较两个四字节整数字段的时间完全一样长。当然,较长的字符串需要较长的时间,但如果代码保持较短,则没有区别。

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

除了上面所说的,还可以考虑使用UUID作为PK。这将允许您创建跨多个数据库的uniq密钥。

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

不可避免地,有几个事实:

1:你肯定会有重复的名字

2:肯定会有名字改变

我永远不会把名字当作主键。

最新更新