GUID与INT IDENTITY的区别

43

可能重复:
你喜欢什么样的主键?

我知道使用GUID和使用数据库中的INT作为PK的好处。考虑到GUID本质上是一个128位的INT,而普通的INT只有32位,因此在大多数现代系统中,INT节省了空间(尽管这一点通常无关紧要)。

最终,在什么情况下您会选择使用INT作为PK,而不是GUID呢?


3
请注意:此问题是在2009年提出的。请参阅http://softwareengineering.stackexchange.com/a/337560/156440和https://dev59.com/Xmct5IYBdhLWcg3wpO7H以获取更多最新的回答,包括指向Kimberley Tripp更新建议的链接。 - JsAndDotNet
13个回答

29

Kimberley Tripp(SQLSkills.com)撰写了一篇关于使用GUID作为主键的文章。她建议不要这样做,因为会带来不必要的开销。


还没有阅读这个系列,但我认为Tony Rogerson在争论使用SSD后,碎片化问题大大减少了。 - Martin Smith
博客文章中的论点,除非我读错了,主要是指使用具有聚集主键(SQL Server)的INT / BIGINT系统和DB将更快且更节省空间。但并非所有数据库都是如此。例如Postgres。 - jmathew
1
她建议不要将唯一标识符作为聚集键。在她的文章或评论中,她指出只要不是聚集键,使用唯一标识符作为主键是可以的。主键不需要是聚集键。 - David Anderson

27

回答你的问题:

最终,在什么情况下,您会使用INT作为主键而不是GUID?

如果我的系统有在线/离线版本,并且在离线版本中可以保存数据并在同步期间将其传输回服务器的一天,则我会使用GUID。这样,您可以确保数据库中不会出现相同的键。


25

我们在我们的复杂企业软件中随处可见Guid。运作顺畅。

我认为,Guid更符合语义要求,适合作为标识符。在面临这个问题之前,不必无端担心性能问题。要警惕过早进行优化。

对于任何类型的数据库迁移,使用Guid也具有优势。使用Guid,您将不会发生冲突。如果尝试合并几个使用整数作为标识符的DB,则必须替换它们的值。如果这些旧值被用于URL中,那么现在将因SEO而产生差异。


1
你们的企业软件中是否考虑了 GUID 集群化? - Koste
我完全同意这个回复,你对像SQL这样的解释性语言如何工作的直觉可能是错误的;在你有一个能告诉你差异的可靠测试之前不要进行优化。至于集群:它会创建争用和热点页面,特别是当你有多个用户都试图写入同一页时。随机键将数据分散到许多页面上并减少争用。 - Quark Soup

23
除了在需要同步多个数据库实例时选择不佳外,INT的一个缺点我没有看到提到:插入总是发生在索引树的一端。当表中有很多移动时(由于并发插入必须修改相同的索引页,而GUID将插入整个索引),这会增加锁争用。如果使用B *树或类似的数据结构,则可能还需要更频繁地重新平衡索引。
当然,INT在手动查询和报告构建时更易于阅读,并且通过FK使用可能会增加空间消耗。
我很想看到例如SQL Server如何处理具有IDENTITY PK的插入密集型表的任何测量结果。

是的,绝对没错。整数或任何单调递增的值在插入和更新期间都会创建热页。如果有几十个用户都在插入和更新,就会为页面创建争用。聚集可能节省空间,但它会为热页创建瓶颈。 - Quark Soup
1
这是我第一次看到这个参数,它是一个非常重要的因素,取决于你有多少写入工作负载相对于读取工作负载。 - maulik13

14

INT类型是空间节省型的(虽然在大部分现代系统中这点通常已经无关紧要)。

并非如此。虽然乍一看是这样,但请注意每个表的主键会在整个数据库中以索引和其他表中的外键形式被多次重复。当它作为连接使用的外键时,在包含其所属表格的任何查询中都将非常频繁地参与其中。

此外,请记住现代CPU运算速度非常快,但是RAM的速度没有跟上。缓存行为因此变得越来越重要。获得良好的缓存行为的最佳方式是具有更小的数据集。因此,尽管4字节和16字节之间的看似微不足道的差异并不总是能产生显著的速度差异,但这是值得考虑的一个方面。


我见过使用int的更好理由之一是,每个索引和表中出现的4个额外字节都会被乘以外键。然而,我认为碎片化问题会使关键字实际使用的空间相形见绌。 - Quark Soup

9

在比较主键和外键关系等值时,INT类型会更快。如果表格被适当地索引且表格较小,则可能不会看到太大的减速,但您必须尝试一下才能确定。 INT也更容易阅读,并与其他人沟通。说“你能看看记录1234吗?”比说“你能看看记录031E9502-E283-4F87-9049-CE0E5C76B658吗?”要简单得多。


3
你可以随时使用hashids来缓解这个问题 http://hashids.org/ - Korayem

7

如果您计划在某个阶段合并数据库,例如多站点复制类型设置,则Guid将节省很多麻烦。但除此之外,我发现Int更容易理解。


6

如果数据存储在单个数据库中(大多数我们编写的应用程序的数据都是如此),那么我会使用 IDENTITY。它很容易使用,旨在以这种方式使用,不会使聚集索引碎片化,并且已经足够了。您将在某些记录数量达到20亿条时耗尽空间(如果使用负值,则为40亿条),但是如果您在一个表中有如此多的记录,那么您肯定会遇到数据仓库问题。

如果数据存储在多个独立的数据库中或与第三方服务进行接口,则我会使用已生成的 GUID。一个很好的例子是数据库中的UserProfiles表通过他们在Active Directory分配给他们的objectGUID将Active Directory中的用户映射到应用程序中的用户配置文件。


4

一些操作系统不再基于唯一硬件特征(CPUID,MAC地址)生成GUID,因为这使得跟踪用户变得太容易(涉及隐私问题)。这意味着GUID的唯一性通常不像许多人想象的那样普遍。

如果您使用数据库的自动ID功能,则该数据库理论上可以确保没有重复。


现在的 GUID 通常是随机生成的。 - Jim Arnold
@Marco,你能提供一些支持这个说法的文档参考吗?我从未听说过这个。 - Ronald Wildenberg
这已经是老掉牙的新闻了。请参阅维基百科http://en.wikipedia.org/wiki/Globally_unique_identifier,特别是算法部分。 - Marco van de Voort

3

我一直认为 PK 应该在可能的情况下是数字。不要忘记,将 GUID 作为 PK 可能意味着它们也会被用作其他表中的外键,所以分页和索引等操作会更加复杂。


如果记录的自然键不是数字,例如日志消息记录的(主机,时间戳)或产品记录的(产品代码),您会坚持添加一个除了具有冗余键之外没有任何作用的数字字段吗? - bignose
不,我不会这样做,但对于时间戳字段,您可以考虑向表中添加一个自增字段,并将其用作密钥,而不是使用时间戳。因为它们都是由数据库生成的。如果它是产品代码,那么我始终会使用该代码作为ID,因为它是根据您的业务确定的产品特定ID,因此将其更改为ID没有意义。这完全取决于您将存储的数据类型以及您将如何设计数据库。 - kevchadders

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