我应该有专门的主键字段吗?
我正在设计一个供Web应用程序使用的小型SQL数据库。
假设某个特定的表具有一个"名称"字段,对于该字段,不允许两行具有相同的值。但是,用户将可以随时更改"名称"字段。
该表中的主键将在其他表中用作外键。因此,如果将"名称"字段用作主键,则任何更改都需要传播到其他表。另一方面,唯一性要求将被自动处理。
我的直觉是添加一个整数字段作为主键,该字段可以由数据库自动填充。拥有这个领域有什么意义吗?还是会浪费时间?
解决方案
出于我们提到的原因,我将自己使用生成的PK。同样,按整数索引和比较比按字符串比较要快。我们也可以在名称字段上放置唯一索引,而不必使其成为主键。
主键对于每一行必须是唯一的。 auto_increment Integer是一个很好的主意,如果我们对填充主键没有其他想法,那么这是最好的方法。
是的,并且根据经验,每张桌子总是如此。
我们绝对不应该将可变字段用作主键,并且在大多数情况下,我们都不希望将具有任何其他用途的字段用作主键。
这是数据库模式的基本良好实践。
从性能的角度来看,拥有整数主键始终是一件好事。使用整数主键,所有关系都将更加高效。例如,JOIN将非常快(SQLServer)。
它还将允许我们将来修改数据库。通常,我们有一个唯一的名称列,只是后来发现它根本不是唯一的。
现在,我们还可以通过在其上也有一个索引来强制Name列的唯一性。
我会使用自动生成的ID字段作为主键。使用基于整数ID的表比文本连接要容易得多。同样,如果字段名称经常更新,如果它是主键,则数据库将承受更大的压力来更频繁地更新该字段上的索引。
如果"名称"字段始终是唯一的,则仍应在数据库中将其标记为唯一。但是,经常会有两个相同名称的可能(可能不是当前的情况,但将来可能是将来的情况),因此,我不建议这样做。
使用ID的另一个优势是,我们对数据库有报表需求。如果我们要使用给定名称的报告,则即使名称可能更改,报告上的ID过滤器也将保持一致。
我们所描述的称为代理密钥。有关详细答案,请参见Wikipedia文章。
如果我们生活在理论数学家的稀缺圈子中(例如C. Date在没有空的地方,因为所有数据值都是已知且正确的),那么可以从数据的组成部分,用于标识我们要引用的理想柏拉图式实体(即姓名+生日+出生地+父母的名字),但在凌乱的现实世界中,"合成键"可以在数据库上下文是一种更实用的处理方式。 (并且可为空的字段可能对我们非常有用。以关系设计理论的人为准!)
记录的主键必须是唯一且永久的。如果记录自然有一个简单的键可以同时满足这两个要求,则可以使用它。但是,它们并不经常出现。对于个人记录,该人的名字既不是唯一的也不是永久的,因此我们几乎必须使用自动递增。
自然键起作用的一个地方是在代码表上,例如,一个将状态值映射到其描述的表。将"活动"的主键设置为1,将"延迟"的主键设置为2,以此类推几乎没有意义。 "延迟"," DLY"; "保留"," HLD"等。
还要注意,有人说我们应该在字符串上使用整数,因为它们比较快。不是真的。比较两个4字节字符字段所需的时间与比较两个4字节整数字段所需的时间完全相同。更长的字符串当然会花费更长的时间,但是如果我们使代码简短,则没有区别。
尽管搜索和连接整数列(如许多人指出的那样)更快,但从一开始就永远不要联接甚至更快。通过存储自然键,通常可以消除联接的需要。
对于较小的数据库,除非对外键引用进行的更改非常频繁,否则它们的CASCADE更新不会对性能产生太大影响。
话虽如此,在这种情况下,我们可能应该使用整数或者GUID作为代理键。可以通过设计更新的主键并不是最好的主意,除非应用程序有一个非常引人注目的业务原因,即名称上要唯一,否则不可避免地会发生冲突。
如果名称列将要更改,那么它并不是主键的理想选择。主键应定义表的唯一行。如果可以更改,那不是真的。在不了解有关系统的更多细节的情况下,我不能说,但这可能是使用代理密钥的好时机。
我还将添加此内容,以消除对所有主键使用自动递增整数的神话。使用它们并不总是可以提高性能。实际上,通常情况恰恰相反。如果我们有一个自动递增的列,则意味着系统中的每个INSERT现在都增加了生成新值的开销。
而且,正如Mark所指出的,如果我们有一系列相关的表,则在所有表上都使用代理ID,要从一个表到另一个表,可能必须将所有这些表连接在一起才能遍历它们。使用自然主键通常不是这种情况。用整数连接6个表通常比用字符串连接2个表要慢。
当所有表上都有自动递增的ID时,我们通常也会失去执行基于集合的操作的能力。现在,我们不必在父表中插入1000行,而是在子表中插入5000行,而是现在必须一次在游标或者其他循环中一次插入父行,以获取生成的ID,以便我们可以分配它们给相关的孩子。我看到30秒的过程变成了20分钟的过程,因为有人坚持要在数据库的所有表上使用自动递增ID。
最后(至少出于我在这里列出的原因,当然还有其他原因),在所有表上使用自动递增ID会导致设计不佳。当设计人员不再需要考虑表的自然键时,通常会导致错误的重复项最终出现在数据中。我们可以尝试避免使用唯一索引的问题,但是以我的经验,开发人员和设计人员无需付出额外的努力,并且在使用新系统一年后,他们发现数据是一团糟,因为数据库没有通过自然键对数据进行适当的约束。
当然有时间使用代理键,但是在所有表上盲目使用它们几乎总是一个错误。