SQL:主键列。人工“Id”列与“自然”列

时间:2011-02-10 17:06:04

标签: sql primary-key rdbms

  

可能重复:
  Relational database design question - Surrogate-key or Natural-key?

当我创建关系表时,有一种诱惑就是选择主键列,这些列的值是唯一的。但出于优化和统一的目的,我每次都会创建人工Id列。如果有一列(或列组合)应该是唯一的,我会为其创建唯一索引,而不是将它们标记为(复合)主键列。

对于主键,是否总是更喜欢人工“Id”列+索引而不是自然列?

6 个答案:

答案 0 :(得分:7)

这是一场宗教辩论。我个人的偏好是使用合成主键而不是自然主键,但双方都有很好的论据。实际上,只要你保持一致和合理,任何一种方法都可以很好地运作。

如果使用自然键,则两个主要缺点是存在复合键和变异主键值。如果您有复合主键,则显然每个子表中必须有多个列。当实体之间存在许多关系时,从数据模型的角度来看,这可能会变得难以处理。但它也会让人们开始查询时感到悲伤 - 创建使用N-1个N连接条件并获得几乎正确结果的查询非常容易。如果你有自然键,你也不可避免地会遇到自然键值发生变化的情况,然后你必须通过许多不同的实体来撼动这种变化 - 这比改变表中的唯一值要复杂得多。

另一方面,如果使用合成密钥,则会通过添加其他列来浪费空间,增加额外开销以维护其他索引,并且会增加您获得功能重复结果的风险。忘记在业务键上创建唯一约束或者看到组合上存在非唯一索引并假设它是唯一索引非常容易。实际上,我几天前被这个特殊的失败所困扰 - 我已经将复合自然键(使用非唯一索引)编入索引,而不是创建一个唯一约束。愚蠢的错误,但相对容易做出。

从查询编写和命名约定的角度来看,我也倾向于选择合成键,因为很高兴知道你何时加入表,A的主键是A_ID而B的主键是是B_ID。这比尝试记住A的主键是A_NAME和A_REVISION_NUMBER的组合以及B的主键是B_CODE更加自我记录。

答案 1 :(得分:2)

这取决于你的自然栏目。如果它们小而且稳定增长,那么它们就是主键的良好候选者。

  • 小 - 密钥越小,单行中的值就越多,索引扫描的速度就越快
  • 稳步增加 - 随着桌子的增长产生更少的索引重新洗牌,从而提高性能。

答案 2 :(得分:2)

通过PRIMARY KEY约束强制执行的密钥与通过UNIQUE约束强制执行的密钥之间几乎没有差别。重要的是,从数据完整性角度强制执行所有必需的密钥。通常这意味着每个表至少一个“自然”键(一个暴露给数据的用户/消费者的键,用于识别关于话语世界的事实)。

您可能还需要创建“技术”键来支持应用程序和数据库功能,而不是最终用户(通常称为代理键)。然而,这应该是次要的考虑因素。为了简单起见(并且通常也是性能),通常只有在您已经确定了特定需求的情况下创建代理键才有意义,而不是之前。

答案 3 :(得分:1)

我的偏好是始终使用人工密钥。

首先它是一致的。任何在您的应用程序上工作的人都知道有一个密钥,他们可以对它做出假设。这使得理解和维护更容易。

我还看到了一些场景,其中自然键(也就是来自HR系统的一个标识员工的字符串)必须在应用程序的生命周期中发生变化。如果您有一个将自然ID链接到员工记录的人工密钥,那么您只需在一个表中更改该自然ID。但是,如果那个自然id是一个主键,并且你把它作为一个外键复制到许多其他表中,那么你的手就会搞得一团糟。

答案 4 :(得分:1)

根据我的拙见,如果我理解你的意思,那么拥有一个人为的Id总是更好。

例如,有些人会使用业务重要的唯一值作为其表ID,我已经在MSDN上阅读过了,甚至在NHibernate官方文档中也提到了一个独特的商业无意义值(人工Id),尽管你想要为该值创建索引以供将来参考。因此,在公司改变其命名的那一天,系统仍将运行完美。

答案 5 :(得分:0)

是的,确实如此。如果不出意外,人工主键的一个最重要的属性是 opacity ,这意味着人工键不会反映任何超出自身的信息;如果你使用自然行内容作为键,你最终会将这些信息暴露给Web界面之类的东西,这对于各种原则来说都是一个糟糕的想法。