数据库中ID字段使用INT还是Unique-Identifier?

34

我正在使用SQL Server 2005(可能在不久的将来是SQL Server 2008)为一个网站创建一个新的数据库。 作为应用程序开发人员,我见过许多使用integer(或bigint等)作为表的ID字段以供关系使用的数据库。 但最近我也见过使用unique identifier (GUID) 作为ID字段的数据库。

我的问题是其中一个是否比另一个更具有优势? integer字段在查询和联接时速度更快吗?

更新:澄清一下,这是用于表中的主键。


6
如果int和GUID的性能是你的数据瓶颈的一个主要担忧因素,那么你应该感到非常幸运。大多数其他应用程序在这成为因素之前会遇到其他更紧迫的问题。 - Joe Chung
4
此外,在执行插入语句时,GUID可能非常有用,因为您可以在C#中创建自己的GUID,然后只需执行插入操作,而无需等待数据库返回新的标识符。 - Jack Marchetti
@Joe Chung 目前还没有性能问题,因为数据库仍在设计中。 - mkchandler
6个回答

57

由于GUIDs具有高度随机性,因此作为集群键存在问题。这个问题在Paul Randal在上一期的Technet Magazine Q&A专栏中得到了解决:我想将GUID用作集群索引键,但其他人认为它会导致索引性能问题。这是真的吗?如果是,你能解释一下原因吗?

现在请记住,讨论的重点是集群索引。您说您希望使用该列作为“ID”,这不清楚是否将其用作集群键还是仅用作主键。通常两者重叠,所以我假设您希望将其用作集群索引。为什么这是一个糟糕的选择,在上面提到的文章链接中有详细说明。

对于非集群索引,GUID仍然存在一些问题,但远没有成为表左侧最重要的集群键时那么大。再次强调,GUID的随机性会导致页面分裂和碎片化,但仅限于非集群索引水平(这是一个较小的问题)。

有很多有关GUID使用的都市传说,指责它们的大小(16字节)与int(4字节)相比,并承诺如果使用它们,则会带来可怕的性能问题。这是略微夸大了。在正确设计的数据模型上,大小为16的键仍然可以是非常高效的键。虽然与int相比大4倍会导致索引中更低密度的非叶子页,但这对绝大多数表格并不是一个真正的问题。B树结构是自然平衡的树,树遍历深度很少成为问题,因此基于GUID键寻找值与基于INT键的性能类似。叶页遍历(即表扫描)不查看非叶页,并且GUID大小对页面大小的影响通常非常小,因为记录本身比GUID引入的额外12个字节要大得多。所以我会对基于“16字节vs. 4”听说建议持谨慎态度。要具体分析每种情况,决定大小对结果的影响:表中有多少其他列(即GUID大小对叶页的影响有多大),以及有多少引用正在使用它(即由于需要存储更大的外键而增加的其他表格数量)。
我在某种程度上在临时为GUID辩护,因为它们最近一直受到负面报道,而有些报道是不应该的。它们有优点,在任何分布式系统中都是必不可少的(一旦你谈论数据移动,无论是通过复制还是同步框架或其他方式)。我见过基于GUID不良声誉做出的错误决策,当它们在没有经过适当考虑的情况下被拒绝时。但确实,如果你必须使用GUID作为聚集键,请确保解决随机性问题:尽可能使用连续的GUID。
最后,回答您的问题:如果您没有使用GUID的特定原因,请使用INT。

这是用作我提到的表中的主键。 - mkchandler
2
如果你有一个聚集索引,请使用NEWSEQUENTIALID()。 - James Westgate
@Reemus 我理解了你的回答,直到最后一句话。如果GUID和INT相似,为什么不使用GUID呢?你回答的前半部分让我觉得它们都可以使用,但是到最后我不确定了。这是因为具有INT的表可能在某个地方具有相同的值吗? - johnny
使用GUID的特定原因是:1)它们是由多个客户端在插入之前生成的,或者2)它们将稍后合并到一个统一的数据库中。对于这两种情况,GUID的真正随机性解决了唯一性问题,并且增加的大小是可以接受的折衷方案。 - Remus Rusanu
那么您的意思是多个客户端、应用程序、数据库等可能具有相同的主键,但由于某种原因,它们现在都需要在同一个数据库中。 - johnny

8

即使使用newsequentialid()函数,GUID比int占用更多的空间并且速度较慢。如果您要进行复制或使用同步框架,则几乎必须使用GUID。


6
INT是4字节,BIGINT是8字节,GUID是16字节。表示数据所需的空间越大,处理它所需的资源就越多——磁盘空间,内存等等。因此(a)它们更慢,但(b)这可能只在数量很大时才有影响(数百万行或成千上万次的事务)。
GUID的优点是它们几乎是全球唯一的。使用适当的算法生成guid(SQL Server xxxx将使用适当的算法),无论你有多少台计算机生成guid,也无论生成频率如何,都不会有两个guid相同。(使用72年后不再适用,我忘记了具体细节)
如果需要在多个服务器上生成唯一标识符,则GUID可能有用。如果需要超过20亿个值的世界级性能,则int可能是可以的。最后但也许最重要的是,如果您的数据具有自然键,请坚持使用它们并忘记替代值。

菲利普,这里的自然键是什么? - johnny
自然键是针对所建模数据的特定键。由于原始问题未提供有关此数据的详细信息,因此我们无法确定它可能是什么。 - Philip Kelley

5

如果你一定需要一个唯一的ID,那么就使用GUID。这意味着如果你将来要合并、同步或复制数据,你应该使用GUID。

对于不太复杂的情况,int类型的ID可能已经足够了,具体取决于表格的增长大小。

像大多数情况一样,正确的答案是:这取决于具体情况。


3

将它们用于复制等,而不是作为主键。

Kimberly L Tripp文章

  • 反对:空间,不严格单调,页面拆分,书签/RIDs等
  • 支持:嗯...

我不会对这篇文章进行投票,因为人们只是不知道而已。我完全同意GUID相比于INTs/BigInts在空间上更加占用。然而,随机GUID CI之所以会遭受页面分裂的唯一原因是因为人们实际上不知道如何正确地维护它们,使其不会分裂。在过去几年中,我已经多次证明,您实际上可以使用随机GUID来预防碎片化。我同意它们对GUID本身的范围扫描确实有影响,但是例如客户和员工表上的IDENTITY列也会产生类似的影响。 - Jeff Moden
我曾进行演示,用58天时间向GUID CI中插入了580万行数据(每天10万行),整个过程不到1%的碎片化且没有进行索引维护。随机GUID实际上是大多数人认为索引应该表现出来的典范。问题在于,人们一直在使用所谓的“最佳实践”索引维护,这实际上是一种“最差实践”,尤其是在使用随机GUID时。 - Jeff Moden

2

完全同意JBrooks的观点。当您的表很大并且使用带有JOIN的SELECT语句时,特别是使用派生表时,使用GUID会显著降低性能。


呵呵...我不会因为你没有提供证据就给你点踩。原因是因为这个网站不赞成引用其他网站的文章。如果你不介意,能否请你提供一个链接,里面有实际的代码来演示你所说的性能问题?谢谢。 - Jeff Moden

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接