对于表之间的外键是否应该链接到自然键或代理键,是否有最佳实践?我真正找到的唯一讨论(除非缺少我的 google-fu)是Jack Douglas 在这个问题中的回答,他的推理对我来说似乎是合理的。我知道除了规则更改之外的讨论,但这将是在任何情况下都需要考虑的事情。
问的主要原因是我有一个遗留应用程序,它使用带有自然键的 FK,但是开发人员强烈推动转向 OR/M(在我们的例子中是 NHibernate),并且一个 fork 已经产生了一些重大更改,因此我希望使用自然键将它们推回正轨,或者移动旧版应用程序以使用 FK 的代理键。我的直觉说要恢复原来的 FK,但老实说,我不确定这是否真的是正确的道路。
我们的大多数表已经定义了代理键和自然键(尽管唯一约束和 PK),因此在这种情况下,必须添加额外的列对我们来说不是问题。我们使用的是 SQL Server 2008,但我希望这对于任何数据库来说都足够通用。
SQL 和关系模型都不会受到引用自然键的外键的干扰。事实上,引用自然键通常会显着提高性能。您会惊讶地发现您需要的信息完全包含在自然密钥中的频率。引用该键会将连接换成更宽的表(从而减少您可以在一页中存储的行数)。
根据定义,您需要的信息始终完全包含在每个“查找”表的自然键中。(术语查找表是非正式的。在关系模型中,所有表都只是表。美国邮政编码表的行可能如下所示:{AK, Alaska}, {AL, Alabama}, {AZ, Arizona}等。大多数人会称之为查找表。)
在大型系统上,找到具有多个候选键的表并不罕见。服务于企业的一部分的表引用一个候选键,而服务于企业的另一部分的表引用不同的候选键也很常见。这是关系模型的优势之一,也是 SQL 很好支持的关系模型的一部分。
当您在也有代理键的表中引用自然键时,您会遇到两个问题。
首先,你会让人们大吃一惊。虽然我通常强烈游说最小意外原则,但这是我不介意让人们感到惊讶的一种情况。当问题是开发人员对外键的逻辑使用感到惊讶时,解决方案是教育,而不是重新设计。
其次,ORM 通常不是围绕关系模型设计的,它们有时会包含不反映最佳实践的假设。(事实上,它们的设计似乎常常没有来自数据库专业人员的输入。)要求在每个表中都有一个 ID 号是这些假设之一。另一种假设是 ORM 应用程序“拥有”数据库。(因此可以自由地创建、删除和重命名表和列。)
在 30 年的时间里,我曾在一个数据库系统上工作,该系统为数百个应用程序提供数据,这些应用程序至少用两打语言编写。该数据库属于企业,而不是 ORM。
引入重大更改的分叉应该是一个展示停止器。
在我曾经工作过的公司,我使用自然键和代理键测量了性能。有一个临界点,代理键开始优于自然键。(假设没有额外的努力来保持自然键的高性能,比如分区、部分索引、基于函数的索引、额外的表空间、使用固态磁盘等。)根据我对那家公司的估计,他们将在大约 2045。与此同时,它们使用自然键获得了更好的性能。
其他相关答案:In Database Schema Confusing
我支持代理键的主要原因是自然键经常会发生变化,这意味着必须更新所有相关的表,这会给服务器带来很大的负担。
在 30 年里,我一直在使用各种数据库来处理许多主题,真正的自然键通常相当罕见。事物被认为是唯一的(SSN)不是,在特定时间唯一的事物以后可能会变得不唯一,并且电子邮件地址和电话号码等某些事物可能是唯一的,但它们可以在以后重新用于不同的人日期。当然,有些东西根本没有像人名和公司名这样的良好唯一标识符。
至于通过使用自然键来避免连接。是的,这可以加快不需要连接的 select 语句,但它会导致您仍然需要连接的地方变慢,因为 int 连接通常更快。它还可能会减慢插入和删除速度,并在密钥更改时导致更新性能问题。复杂的查询(反正更慢)会更慢。所以简单的查询速度更快,但报告和复杂的查询以及针对数据库的许多操作可能会更慢。这是一种平衡行为,根据查询数据库的方式,可能会以一种或另一种方式倾斜。
所以没有一刀切的答案。这取决于您的数据库以及查询方式以及其中存储的信息类型。您可能需要进行一些测试以找出最适合您自己的环境的方法。
如果您不知道答案,请选择代理人。这就是为什么 - 如果对业务规则做出假设,并且这些假设是错误的或规则发生变化,那么您的数据就是垃圾。这是一个例子:
人物、角色、人物角色
当前的业务规则规定一个人只有一个角色。您制作了一个将 Person 和 Role 链接起来的表,其中 PersonRole (PersonName, PersonBirthDate, PersonMotherMaidenName, ..., RoleCode)
现在,当谈到 Natural Keys 时,您是真正的纯粹主义者!但说真的,如果组织决定一个人现在可以担任多个角色怎么办?支持业务需求变化的下游效应是什么?