【问题标题】:INT vs Unique-Identifier for ID field in database数据库中 ID 字段的 INT 与唯一标识符
【发布时间】:2010-11-12 04:54:55
【问题描述】:

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

我的问题是,一个人是否比另一个人更有优势? integer 字段在查询和加入等方面会更快吗?

更新:为了清楚起见,这是针对表中的主键。

【问题讨论】:

  • 如果 int 与 GUID 的性能是您的数据瓶颈问题的主要来源,请认为自己非常很幸运。在这成为一个因素之前,大多数其他应用程序都会遇到其他更紧迫的问题。
  • 另外,GUID 在执行插入语句时很有用,因为您可以在 C# 本身中创建您的 GUID,然后只需执行插入,而不必等待数据库返回新标识符。
  • @Joe Chung 目前没有性能问题,因为数据库还在设计中。

标签: sql sql-server tsql uniqueidentifier


【解决方案1】:

由于高随机性,GUID 作为集群键存在问题。此问题由 Paul Randal 在上一期 Technet 杂志问答专栏中解决:I'd like to use a GUID as the clustered index key, but the others are arguing that it can lead to performance issues with indexes. Is this true and, if so, can you explain why?

现在请记住,讨论专门针对聚集索引。您说您想将该列用作“ID”,但不清楚您是指它作为聚集键还是主键。通常这两个重叠,所以我假设您想将它用作聚集索引。我上面提到的文章的链接解释了为什么这是一个糟糕的选择。

对于非聚集索引,GUID 仍然存在一些问题,但不如它们是表的最左侧聚集键时那么大。同样,GUID 的随机性引入了页面拆分和碎片,仅在非聚集索引级别(一个小得多的问题)。

围绕 GUID 的使用有许多都市传说,它们根据它们的大小(16 字节)与 int(4 字节)相比来谴责它们,并承诺如果使用它们会带来可怕的性能厄运。这有点夸张。在正确设计的数据模型上,大小为 16 的键仍然可以是非常高性能的键。虽然确实是 int 的 4 倍会导致索引中的非叶页密度更低更多,但这对于绝大多数表来说并不是一个真正的问题。 b-tree 结构是一种自然平衡的树,并且树遍历的 深度 很少成为问题,因此基于 GUID 键而不是 INT 键来寻找值在性能上是相似的。叶页遍历(即表扫描)不查看非叶页,GUID 大小对页大小的影响通常很小,因为记录本身明显大于引入的额外 12 个字节通过 GUID。因此,我会接受基于“是 16 字节与 4 字节”的传闻建议,并带有相当大的盐粒。逐个分析并确定大小影响是否真正产生影响:表中有多少 other 列(即 GUID 大小对叶页的影响有多大)以及有多少列引用正在使用它(即,有多少 other 表会增加,因为它们需要存储更大的外键)。

我在对 GUID 的一种临时辩护中提到所有这些细节,因为他们最近受到了很多负面新闻,有些是不值得的。它们有其优点,并且在任何分布式系统中都是必不可少的(当您谈论数据移动时,无论是通过复制还是同步框架或其他方式)。我已经看到当他们在没有适当考虑的情况下被回避时,基于 GUID 的坏名声做出了错误的决定。但确实如此,如果您必须使用 GUID 作为集群键,请确保解决随机性问题:尽可能使用顺序 guid

最后,回答您的问题:如果您没有特定理由使用 GUID,请使用 INT。

【讨论】:

  • 这是用作我提到的表中的主键。
  • 如果您有聚集索引,请使用 NEWSEQUENTIALID()。
  • @Reemus 直到最后一句话我才明白。如果它们相似,为什么不使用 GUID?您回答的第一部分让我认为他们一切都很好,但最后我不确定。是因为带有 INT 的表在某处可能具有相同的值吗?
  • 使用 GUID 的具体原因是:1) 它们是客户端生成的(插入之前),由多个客户端或 2) 它们稍后将合并到统一数据库中。对于这两种情况,GUID 的真正随机性解决了唯一性问题,增加的大小是可以接受的权衡。
  • 所以您的意思是多个客户端、应用程序、数据库等,它们可能具有相同的 PK,但无论出于何种原因,它们现在都需要位于同一个数据库中。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    INT 为 4 个字节,BIGINT 为 8 个字节,GUIDS 为 16 个字节。表示数据所需的空间越多,处理它所需的资源就越多——磁盘空间、内存等。所以(a)它们速度较慢,但​​是(b)这可能仅在容量问题(数百万在非常非常短的时间内完成行或数千个事务。)

    GUID 的优势在于它们(几乎)是全球唯一的。使用正确的算法生成一个 guid(并且 SQL Server xxxx 将使用正确的算法),并且没有两个 guid 永远是相同的——无论您有多少台计算机生成它们,无论多么频繁。 (这在使用 72 年后不适用——我忘记了细节。)

    如果您需要跨多个服务器生成唯一标识符,GUID 可能会很有用。如果您需要 mondo 性能和低于 20 亿的值,int 可能没问题。最后,也许也是最重要的一点,如果您的数据具有自然键,请坚持使用它们并忘记代理值。

    【讨论】:

    • 菲利普,这里的自然键是什么?
    • 自然键特定于被建模的数据。原始问题不包含有关此数据的详细信息,因此我们无法确定它可能是什么。
    【解决方案4】:

    如果你肯定,绝对必须有一个唯一的 ID,然后是 GUID。这意味着如果您要合并、同步、复制,您可能应该使用 GUID。

    对于不太健壮的东西,一个 int 就足够了,具体取决于表的大小。

    在大多数情况下,正确的答案是视情况而定。

    【讨论】:

      【解决方案5】:

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

      Kimberly L Tripp article

      • 反对:空格、非严格单调、页面拆分、书签/RID 等
      • 对于:呃...

      【讨论】:

      • 我不会投反对票,因为人们只是不知道。我绝对同意,与 INT/BigInts 相比,GUID 在空间上要困难得多。但是,Random GUID CI 遭受页面拆分的唯一原因是人们实际上并不知道如何正确维护它们,因此它们不会拆分。在过去几年中,我已经多次证明您实际上可以使用随机 GUID 来防止碎片。我同意他们这样做是为了对 GUID 本身进行范围扫描,但例如 Customer 和 Employee 表上的 IDENTITY 列也是如此。
      • 我已经给出了演示,其中我在 58 天的时间内(每天 10 万行)将 580 万行插入到 GUID CI 中,整个过程中碎片
      【解决方案6】:

      完全同意 JBrooks。 我想说的是,如果您的表很大,并且您使用 JOINS 选择,尤其是派生表,使用 GUID 会显着降低性能。

      【讨论】:

      • 嘿...我不会因为您没有提供任何证据而对此投反对票。之所以如此,是因为本站便便引用了其他网站的文章。如果您不介意,请问您是否有可以发布的链接,其中包含实际代码来演示您所谈论的性能问题?谢谢
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-26
      • 2023-04-08
      • 2010-11-27
      • 1970-01-01
      相关资源
      最近更新 更多