2008-11-04 113 views
17

我目前正在通过查找表生成主键的数据库,其中包含表名列表和最后使用的主键。一个存储过程增加这个值并在返回到调用'insert'SP之前检查它是唯一的。不使用主键的自动递增号码的原因

使用这种方法(或只是生成一个GUID)而不是仅仅使用身份/自动编号有什么好处?

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

谢谢。

回答

27

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

如果你不太可能使用复制,那么一个自动递增的PK很可能会工作得很好。

+0

你能举一个复制的例子吗?我们不能在复制时使用自动生成的ID的身份插入吗? – ivorykoder 2013-07-18 16:28:51

+0

@ivorykoder如果两个数据库都生成一个新行(并因此生成一个新ID),然后尝试同步,则表中的两个不同行将具有不同的PK,这会有冲突。如果您使用GUID,PK实际上保证是唯一的。 – Matthew 2016-10-31 12:02:19

6

递增的过程方法必须是线程安全的。如果不是,您可能无法获得唯一的号码。此外,它必须快速,否则将是一个应用程序瓶颈。内置功能已考虑到这两个因素。

2

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

6

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

3

使用唯一标识符将允许您合并来自两个不同数据库的数据。

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

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

1

我能想到的唯一理由是,该代码被写入之前sequences被发明和代码忘了追赶;)

+0

对。我们最早的应用程序之一的数据库采用了本地化的方法,使用序列表(基本上是描述的),因为MySQL当时不支持它们(或者可能是错误的)。这些表格依然存在,但我们现在一直在使用真实的东西。 – MBCook 2008-11-04 17:24:44

1

我宁愿使用GUID大部分场景在这篇文章的目前的方法对我来说意义重大(复制是可能的)。如果复制是个问题,那么这样一个存储过程必须意识到其他服务器必须链接以确保密钥的唯一性,这会使其非常脆弱,并且可能是一种糟糕的方式。
我使用不是自动递增身份的整数主键的一种情况是,强制外键约束的很少更改的查找表的情况,这些查询表在数据消耗应用程序中将具有相应的枚举。在这种情况下,我想确保在开发和部署之间enum映射是正确的,特别是如果将有多个prod服务器。

0

这样做的唯一真正原因是数据库不可知(如果不同的数据库版本使用不同的自动编号技术)。

这里提到的另一个问题是能够在多个地方创建记录(如在中心办公室以及在旅行用户的笔记本电脑上)。不过,在这种情况下,您可能需要类似于每个安装所独有的“站点代码”,而每个安装都以每个ID为前缀。

1

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

17

使用自动编号没有任何内在的错误,但有几个理由不这样做。正如dacracot提到的那样,推出自己的解决方案并不是最好的主意。让我解释。

不使用每个表上的自动编号的第一个原因是您可能最终合并来自多个表的记录。假设您有销售订单表和其他类型的订单表,并且您决定提取一些常见数据并使用多个表继承。拥有全局唯一的主键很不错。这与bobwienholt关于合并数据库的说法类似,但它可能发生在数据库中。其次,其他数据库不使用这种范式,其他范例如Oracle的序列更好。幸运的是,可以使用SQL Server模拟Oracle序列。一种方法是为整个数据库创建一个名为MainSequence的AutoNumber表,或者其他的。数据库中没有其他表将使用自动编号,但任何需要自动生成主键的人都将使用MainSequence来获取它。通过这种方式,您可以获得所有内置的性能,锁定,线程安全性等等,而不需要自己构建它。

另一种方法是使用GUID作为主键,但我不建议这样做,因为即使您确定人类(甚至是开发人员)永远不会读取它们,也可能有人会这样做,而且很难。更重要的是,在T-SQL中隐式地转换为整型,但隐式转换为GUID可能会遇到很多麻烦。基本上它们不方便。

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

10

CodingHorror

GUID优点

  • 独特的横跨每个表,每个数据库,每个服务器
  • 从不同的数据库允许的记录很容易合并
  • 允许跨多个数据库易于分发服务器
  • 您可以在任何地方生成身份证,而不必往返数据库
  • 大多数复制方案需要GUID列反正

GUID缺点

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

本文提供了许多关于在GUID与自动递增上做出决定的良好外部链接。如果可以,我用GUID去。

0

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

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

0

我自动递增键的主要问题是它们缺少任何含义。

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

3

我有自动递增键主要问题是,他们没有任何意义

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

0

Galwegian的回答不一定是正确的。

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

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

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

这意味着

DB1将具有键1,3,5,7 ....

DB2将有键2,4,6,8 ....

因此,我们不会有关于插入的关键冲突。

2

这里是有自动递增的整数作为钥匙的东西:你必须有张贴记录你访问它之前

。这意味着,除非您发布记录,否则不能准备将存储在另一个表中的相关记录,或者为什么访问新记录的唯一性可能会有帮助的其他可能原因中的任何一个ID,之后发布。

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