不对主键使用自动递增编号的原因

时间:2008-11-04 17:12:18

标签: sql-server primary-key

我正在处理其他人的数据库,其中主键是通过查找表生成的,该查找表包含表名列表和最后使用的主键。存储过程会递增此值并在将其返回到调用“插入”SP之前检查它是唯一的。

使用这样的方法(或仅生成GUID)而不仅仅使用身份/自动号码有什么好处?

我不是在谈论实际上意味着像ISBN或产品代码这样的主键,而只是唯一的标识符。

感谢。

16 个答案:

答案 0 :(得分:27)

自动生成的ID可能会在您使用复制的情况下导致问题(因为我确定您找到的技术可以!)。在这些情况下,我通常会选择GUID。

如果您不太可能使用复制,那么自动递增PK很可能会正常工作。

答案 1 :(得分:17)

使用自动编号没有任何内在错误,但有几个原因不能这样做。尽管如此,正如dacracot所提到的,滚动自己的解决方案并不是最好的主意。让我解释一下。

不在每个表上使用自动编号的第一个原因是您可能最终合并来自多个表的记录。假设您有一个销售订单表和一些其他类型的订单表,并且您决定提取一些常见数据并使用多个表继承。拥有全球唯一的主键是很好的。这类似于bobwienholt关于合并数据库的内容,但它可以在数据库中发生。

其次,其他数据库不使用此范例,其他范例(如Oracle的序列)更好。幸运的是,可以使用SQL Server模拟Oracle序列。一种方法是为整个数据库创建一个名为MainSequence的AutoNumber表,或者其他。数据库中没有其他表将使用自动编号,但任何需要自动生成主键的人都将使用MainSequence来获取它。通过这种方式,您可以获得dacracot所讨论的所有内置性能,锁定,线程安全等,而无需自己构建它。

另一个选择是使用GUID作为主键,但我不建议这样做,因为即使你确定一个人(甚至是开发人员)永远不会阅读它们,有人可能会,而且很难。更重要的是,事情在T-SQL中很容易被隐含地强制转换为内容,但是隐式地转换为GUID会有很多麻烦。基本上,它们很不方便。

在构建新系统时,我建议使用专用表来生成主键(就像Oracle序列一样)。对于现有的数据库,我不会忘记改变它。

答案 2 :(得分:10)

来自CodingHorror

GUID专业人士

  • 每个表,每个数据库,每个服务器都是唯一的
  • 允许轻松合并来自不同数据库的记录
  • 允许跨多个服务器轻松分发数据库
  • 您可以在任何地方生成ID,而不必转发到数据库
  • 大多数复制方案都需要GUID列

GUID缺点

  • 比传统的4字节索引值大4倍;如果你不小心,这会产生严重的性能和存储影响
  • 调试繁琐(其中userid ='{BAE7DF4-DDF-3RG-5TY3E3RF456AS10}')
  • 生成的GUID应该是部分顺序的,以获得最佳性能(例如,SQL 2005上的newsequentialid())并启用聚簇索引

本文提供了很多关于GUID与自动增量决策的良好外部链接。如果可以的话,我会选择GUID。

答案 3 :(得分:6)

递增的过程方法必须是线程安全的。如果没有,您可能无法得到唯一的数字。此外,它必须很快,否则将成为应用程序的瓶颈。内置函数已经考虑了这两个因素。

答案 4 :(得分:6)

客户端能够预先分配一大堆ID来执行批量插入,而不必使用插入的ID更新其本地对象。然后是整个复制问题,如Galwegian所述。

答案 5 :(得分:3)

使用唯一标识符可以合并来自两个不同数据库的数据。

也许您有一个应用程序可以在多个数据库中收集数据,然后在当天的不同时间与主数据库“同步”。在这种情况下,您不必担心主键冲突。

或者,您可能想知道在创建记录之前记录的ID是什么。

答案 6 :(得分:3)

  

自动递增键的主要问题是它们没有任何含义

在我看来,这是主键的要求 - 除了识别记录之外没有其他理由存在。如果它没有真实世界的意义,那么就没有真正的改变理由。一般来说,您不希望更改主键,因为您必须搜索 - 替换整个数据库或更糟。我一直对我所认为的那些独特且不变的事情感到惊讶,这些事情在几年之后还没有发现。

答案 7 :(得分:3)

这是将自动递增整数作为键的事情:

您必须先发布记录才能访问该记录。这意味着,在您发布记录之前,您不能,例如,准备将存储在另一个表中的相关记录,或者许多其他可能的原因中的任何一个可能有助于访问新记录的唯一原因id,发布之前。

以上是我的决定因素,无论是采用一种方法还是另一种方法。

答案 8 :(得分:2)

一个好处是它可以允许数据库/ SQL更加跨平台。 SQL可以在SQL Server,Oracle等上完全相同......

答案 9 :(得分:1)

我能想到的唯一原因是代码是在sequences被发明之前编写的,代码忘了追赶;)

答案 10 :(得分:1)

我更喜欢在帖子的当前方法对我有意义的大多数场景中使用GUID(复制是可能的)。如果复制是个问题,那么这样的存储过程就必须知道必须链接的另一个服务器以确保密钥的唯一性,这会使它变得非常脆弱,并且可能是一种不好的方式。
我使用不是自动递增标识的整数主键的一种情况是很少更改的查找表强制执行外键约束,这将在数据消耗应用程序中具有相应的枚举。在那种情况下,我想确保枚举映射在开发和部署之间是正确的,特别是如果有多个prod服务器的话。

答案 11 :(得分:1)

另一个可能的原因是你故意想要随机密钥。例如,如果您不想让爱管闲事的浏览器浏览数据库中的每个项目,这可能是理想的,但这并不足以保证实际的身份验证安全措施。

答案 12 :(得分:0)

执行此操作的唯一真正原因是与数据库无关(如果不同的db版本使用不同的自动编号技术)。

这里提到的另一个问题是能够在多个地方创建记录(例如在中央办公室以及旅行用户的笔记本电脑上)。但是,在这种情况下,您可能需要类似“站点代码”的内容,这些内容对于每个ID都是唯一的。

答案 13 :(得分:0)

使用GUID主键而不是自动递增主键的一个有用的附带好处是,您可以在客户端为新行分配PK值(实际上您必须在复制方案中执行此操作),免除你检索刚刚在服务器上添加的行的PK的麻烦。

GUID PK的一个缺点是GUID字段上的连接速度较慢(除非最近已更改)。使用GUID的另一个好处是,尝试向非技术经理解释为什么GUID冲突不太可能,这很有趣。

答案 14 :(得分:0)

自动递增键的主要问题是它们没有任何意义。

对于某些字段提供唯一性的表格(无论是单独使用还是与其他字段组合使用),我都会选择使用它。

答案 15 :(得分:0)

Galwegian的答案不一定如此。

使用MySQL,您可以为每个数据库实例设置键偏移量。如果你将它与足够大的增量结合起来就可以了。我相信其他供应商会有类似的设置。

假设我们有2个我们想要复制的数据库。我们可以通过以下方式进行设置。

increment = 2
db1 - offset = 1
db2 - offset = 2

这意味着

db1将拥有密钥1,3,5,7 ....

db2将拥有密钥2,4,6,8 ....

因此我们不会在插入物上发生关键冲突。