SQL GUID 和整数之间有什么区别?

15

我最近开始了一份新工作,注意到所有的SQL表都使用GUID数据类型作为主键。

在我的上一份工作中,我们使用整数(自增)作为主键,在我看来更容易处理。

例如,假设您有两个相关的表; Product和ProductType-我可以轻松地交叉检查这两个表的“ProductTypeID”列以获取特定行,以便快速在我的脑海中映射数据,因为它很容易将数字(2,4,45等)存储为(E75B92A3-3299-4407-A913-C5CA196B3CAB)。

额外的挫败感来自于我想要理解表之间的关系,但遗憾的是没有数据库图 :(

很多人说GUID更好,因为你可以在你的C#代码中定义唯一标识符,例如使用NewID()而不需要SQL SERVER来完成 - 这也允许你暂时知道ID是什么... 但是我已经看到了可以仍然检索'下一个自动递增的整数'

一位DBA承包商报告说,如果我们使用整数类型而不是GUIDS,我们的查询可能会快30%...

GUID数据类型为什么存在,它真正提供了什么优势?...即使是由某些专业人士做出的选择,也一定有一些好的理由为什么要实现它吧?


可能是GUID vs INT IDENTITY的重复问题。 - Jeremiah Willcock
6个回答

18

在某些情况下,GUID可以作为身份字段使用:

  • 当您有多个SQL实例(不同的服务器)并且需要将不同的更新组合起来而不影响引用完整性时。
  • 未连接到服务器的客户端创建数据 - 这样,他们可以创建数据而不必担心ID字段已被占用。

GUID生成为全局唯一,这就是为什么它们适合于这些情况的原因。


好的,现在这其实很有道理,因为我遇到过需要重新插入一些数据而自增列变成噩梦的情况...使用GUID就不会出现这个问题...谢谢 :) - Dalbir Singh

15

与这里的大多数人所宣扬的相反,我认为 GUID 不是一种神器而是一种灾难。以下是原因:

GUID 看起来似乎是作为主键的自然选择——如果您确实需要,可能可以争辩使用它作为表的 PRIMARY KEY。但我强烈建议不要将 GUID 列用作聚集键(clustering key),这是 SQL Server 的默认设置,除非您明确告诉它不要这样做。

您真的需要将两个问题分开:

  1. 主键(primary key)是一个逻辑构造——唯一可靠地标识表中每一行的候选键之一。这可以是任何东西——一个 INT,一个 GUID,一个字符串——选择对您的情况最有意义的。

  2. 聚集键(clustering key)(定义表上的"聚集索引(clustered index)"的列)——这是与物理存储相关的事情,在这里,稳定且不断增长的数据类型是最好的选择——INT或BIGINT作为默认选项。

默认情况下,SQL Server 表上的主键也被用作聚集键——但不必如此!我亲自看到了当将以 GUID 为基础的 Primary/Clustered Key 分成两个单独的键时,性能显著提高——主键(逻辑)在 GUID 上,而聚集(排序)键在一个单独的 INT IDENTITY(1,1) 列上。

正如索引女王Kimberly Tripp和其他人多次指出的那样,GUID 作为聚集键并不是最佳选择,因为由于其随机性,它将导致大量页面和索引碎片化以及通常的糟糕性能。

是的,我知道——在 SQL Server 2005 及更高版本中有 newsequentialid(),但即使如此,它也不是真正和完全的顺序的,因此也会遇到 GUID 相同的问题,只是稍微不那么明显而已。此外,您只能将其用作表中列的默认值,无法在 T-SQL 代码(如触发器之类)中获取新的连续 GUID——这是另一个主要缺点。

然后还有另一个问题需要考虑:表上的聚集键还将添加到每个非聚集索引上的每个条目中——因此,您确实希望确保它尽可能小。通常,具有 20 多亿行的 INT 对于绝大多数表来说应该足够了——与作为聚集键的 GUID 相比,您可以在磁盘和服务器内存上节省数百兆字节的存储空间。

快速计算——使用 INT 与 GUID 作为主键和聚集键:

  • 基本表格具有 1,000,000 行(3.8 MB vs. 15.26 MB)
  • 6 个非聚集索引(22.89 MB vs. 91.55 MB)

总计:25 MB vs. 106 MB ——仅仅是单个表格!

还有一些关于此的值得考虑的东西——Kimberly Tripp 提供的绝妙内容——阅读它,再次阅读它,领会它!这是 SQL Server 索引福音的真谛。

  • 越来越大的聚集键 - 聚集索引辩论...... 再次发生!
  • 马克


    6

    INT

    优点:

    在联接、索引和条件中使用数值(尤其是整数)的性能更优。 如果显示数字,应用程序用户更容易理解。

    缺点:

    如果您的表很大,则有可能会用完它,一些数值之后将没有其他标识可用。

    GUID

    优点:

    在整个服务器上唯一。

    缺点:

    与整数值相比,字符串值在联接、索引和条件中的性能不够优异。 需要比 INT 更多的存储空间。

    来源: http://blog.sqlauthority.com/2010/04/28/sql-server-guid-vs-int-your-opinion/


    1
    我怀疑很少有人会拥有比4字节整数(20亿)更多的行,甚至更少的人会超过8字节BIGINT的极限:9,223,372,036,854,775,807。如果确实需要更多,可以使用负数并将行数加倍。 - KM.
    INT的缺点可以通过必要时使用BIGINT轻松克服。至少在Mysql上,这是一个64位整数,您永远不会有那么多记录,而且它仍然只有GUID大小的50%。使用GUID的唯一原因是可扩展性。如果确实想使用GUID,大多数数据库允许将GUID存储为二进制而不是十六进制字符串,这样可以节省一半的存储空间并加快索引速度。 - wump
    在SQL Server中,将GUID作为聚集键存在一个非常大的缺点:由于索引和页面的大量碎片化,性能非常糟糕。请查看我回答中提到的文章,并重新考虑一下。GUID很方便,但它们会让数据库管理员的噩梦成真... - marc_s
    实际上,GUID代表全局唯一标识符,因此它们不仅在服务器上是唯一的,而且在整个服务器群中也是唯一的。因此,您可以非常轻松地跨集群合并数据集。如果每个服务器都将记录PK表示为INT,并且相同的INT表示不同的记录,则无法执行此操作。 - user177800

    3

    有很多关于使用GUID作为主键的可搜索文章,几乎所有这些文章都说与您的数据库管理员承包商所说的一样--如果没有GUID作为键,则查询速度更快。

    实际使用中我见过的主要用途(我们从未将它们用作主键)是复制。MSDN页面uniqueidentifier也说了同样的话。


    感谢您的输入,没错,他们正在PK上使用它们,这就是使得在行之间进行虚拟导航变得困难的原因。 - Dalbir Singh
    是的,使用复制和 GUID 作为主键可能是有意义的。但即使如此,我仍然会尽量避免(像瘟疫一样)将该 GUID 列作为表上的聚集键! - marc_s

    2

    GUID是全球唯一的,因此您表中的每条记录都有一个GUID,在世界上任何其他项目中都没有共享。如果您需要这种独特的标识(如果您正在复制数据库或组合来自多个来源的数据),那么这非常方便。否则,您的数据库管理员是正确的 - GUID比整数大得多且效率低下,您可以加速您的数据库(也许30%?)。


    是的,我可以看出在“复制数据”时,这将非常有利,并消除自动递增列所带来的限制。数据库设计并不是我见过的最好的 - 我可以相信会有30%的改进哈哈。 - Dalbir Singh

    0

    它们基本上可以帮助你避免使用更加复杂的逻辑

    set @InsertID = scope_identity() 
    

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