【问题标题】:Is there any better option for GUID creation than System.Guid.NewGuid() in .net有没有比 .net 中的 System.Guid.NewGuid() 更好的 GUID 创建选项
【发布时间】:2012-06-29 14:07:02
【问题描述】:

在我的应用程序代码中,我使用System.Guid.NewGuid() 生成 GUID 并将其保存到 SQL Server DB。

我有几个关于 GUID 生成的问题:

  1. 当我运行程序时,我没有发现这在性能方面有任何问题,但我仍然想知道我们是否有其他更好的方法来生成 GUID。
  2. System.Guid.NewGuid() 这是在 .NET 中创建 GUID 的唯一方法 代码?

【问题讨论】:

  • 是什么让您认为有更好的方法? (事实上​​,即使在原则上,为什么会有更好的方式存在?如果有更好的方式,那将是Guid.NewGuid的实现所使用的方式。)
  • 你也可以在SQL中使用NEWID()来实现,但是你提到的方式是在代码中实现的方式。
  • Eric Lippert 在他的博客上发布了一系列关于 GUID 及其生成(.net 内部和外部)的文章,我带走的一点是,使用他们用来生成 Guid 的方法非常罕见查看 Guid 冲突。我的主要问题是,为什么您需要一种比.Net 使用的方法更好的方法? blogs.msdn.com/b/ericlippert/archive/2012/04/24/…
  • 您想改进什么?结果应该是 a) 更全球化、b) 更独特还是 c) 识别更好?
  • 是的,可能是 d) 更顺序。 @Usr 有一个很好的答案。

标签: c# asp.net sql visual-studio-2010 sql-server-2008


【解决方案1】:

Guid.NewGuid 生成的 GUID 根据 SQL Server 排序顺序不是连续的。这意味着您将随机插入到索引中,这对性能来说是一场灾难。如果写入量足够小,则可能无关紧要。

您可以使用 SQL Servers NEWSEQUENTIALGUID() 函数来创建连续的,或者只使用一个 int。

【讨论】:

  • 为什么对性能来说是一场灾难?如果每个人都按顺序插入,每个 writer 都将争夺表中的最后一页,从而有效地序列化所有 writer。
  • @Gabe,这是 very 高插入情况下的问题。在这种情况下,您要做的就是在 N 个位置按顺序插入 B 树(N = 核心数左右)。千万不要随意,如果你能帮助它,因为它会导致疯狂的碎片和缓存抖动。
  • @urs 你能建议我在 .net 代码中生成顺序 GUID 的方式吗?
  • 这个看起来不错:developmenttips.blogspot.de/2008/03/…(我自己也用类似的方式实现过这样的东西)。
  • @urs 在链接中引用了“SQL Server 中的 GUID 列不应该是连续的”你知道为什么吗?
【解决方案2】:

另一种生成 guid 的方法(我认为是您的 PK)是像这样设置表格中的列:

create table MyTable(
    MyTableID uniqueidentifier not null default (newid()),
...

这样实现意味着您可以选择是在 .Net 中设置它们还是让 SQL 来做。

不过,我不会说“更好”或“更快”。

【讨论】:

    【解决方案3】:

    回答问题:

    有没有比创建 GUID 更好的选择 .net 中的 System.Guid.NewGuid()

    我敢说 System.Guid.NewGuid() 是首选。

    但是对于后续问题:

    ...将其保存到 SQL Server 数据库。

    答案不太清楚。这在网上已经讨论了很长时间。只需 Google“guid as primary key”,您将有数小时的阅读时间。

    通常当您在 Sql 服务器中使用 Guid 时,它是因为在表中用作主键。这有很多好处:

    • 无需访问数据库即可轻松生成新值
    • 您可以合理地确定本地生成的 Guid 不会导致主键冲突

    但也有明显的缺点:

    • 如果主键也是聚集索引,插入大量新行会导致大量 IO(磁盘操作)和索引更新。
    • 与代理键的其他流行替代项 int 相比,Guid 相当大。由于表上的所有其他索引都包含聚集索引键,因此如果您使用 Guid 与 int,它们的增长速度会更快。
    • 这也会导致更多 IO,因为这些索引需要更多内存

    为了缓解 IO 问题,Sql Server 2005 引入了一个新的 NEWSEQUENTIALGUID() 函数,可用于在插入新行时生成顺序 Guid。但是,如果您打算使用它,那么您将必须与数据库联系才能生成一个,因此您在离线时失去了生成一个的可能性。在这种情况下,您仍然可以生成一个普通的 Guid 并使用它。

    网上也有很多关于如何滚动您自己的顺序指南的文章。一个样本:

    http://www.codeproject.com/Articles/388157/GUIDs-as-fast-primary-keys-under-multiple-database

    我没有测试过它们中的任何一个,所以我不能保证它们有多好。我选择了那个特定的样本,因为它包含一些可能很有趣的信息。具体来说:

    它变得更加复杂,因为微软的一个怪癖 SQL Server 是它根据最少排序 GUID 值 重要的六个字节(即 Data4 块的最后六个字节)。 所以,如果我们想创建一个顺序 GUID 用于 SQL Server,我们 必须将顺序部分放在最后。大多数其他数据库 系统会在一开始就需要它。

    编辑:由于问题似乎与使用批量复制插入大量数据有关,因此可能需要顺序 Guid。如果在插入之前不需要知道 Guid 值,那么 Jon Egerton 的答案将是解决问题的一种好方法。如果您需要事先知道 Guid 值,则必须生成顺序 Guid 以在插入时使用或使用解决方法。

    一种可能的解决方法是更改​​表以使用种子 INT 作为主键(和聚集索引),并将 Guid 值作为具有唯一索引的单独列。插入时,Guid 将由您提供,而种子 int 将是聚集索引。然后将按顺序插入行,您生成的 Guid 仍可用作稍后获取记录的备用键。我不知道这是否对您来说是一个可行的解决方案,但它至少是一种可能的解决方法。

    【讨论】:

      【解决方案4】:

      NewGuid 是一般推荐的方式 - 除非您需要顺序值,在这种情况下,您可以 P/Invoke 到 rpcrt 函数UuidCreateSequential

      Private Declare Function UuidCreateSequential Lib "rpcrt4.dll" (ByRef id As Guid) As Integer
      

      (对不起,从 VB 中删除,请确保您可以转换为 C# 或其他 .NET 语言as required)。

      【讨论】:

      • 小心:SQL Server 的排序顺序可能与此不同。使用前需要检查。
      • @usr - 我们仍然不知道 OP 使用什么定义来表示“更好”,所以谁知道呢?
      猜你喜欢
      • 2019-08-15
      • 1970-01-01
      • 2021-10-11
      • 2022-11-15
      • 2021-04-21
      • 2012-01-20
      • 2012-05-08
      • 2010-09-22
      • 1970-01-01
      相关资源
      最近更新 更多