【问题标题】:Are GUID collisions possible?是否可能发生 GUID 冲突?
【发布时间】:2010-09-16 03:20:40
【问题描述】:

我正在开发 SQL Server 2000 中的数据库,该数据库为使用与其关联的应用程序的每个用户使用一个 GUID。不知何故,两个用户最终使用了相同的 GUID。我知道微软使用一种算法来生成随机 GUID,它导致冲突的可能性极低,但仍然可能发生冲突吗?

【问题讨论】:

  • 每个人说不都是错的。我已经将 1 个 UniqueIdentifier 与不到 50 万条记录的数据集相冲突,MSSQL 2008 R2
  • @Behrooz Yikes。感谢我们的朋友生日悖论,这并非不可能,但是对于完全随机的 v4 GUID,它仍然非常不幸。也许您使用的是较弱的 GUID 生成策略?
  • @Behrooz 哇。这真是令人震惊的运气。
  • @Behrooz 这可能是 MSSQL 中使用的有缺陷的伪随机数(如果他们的生成器中有 32 位种子,或者考虑到他们的软件质量,我不会感到惊讶)。数学不会说谎。这种可能性是如此之小,以至于您可能是 99.9999999999(以及之后的很多 9)% MSSQL guid 生成器有缺陷(或者可能是用于生成 GUID 的伪随机生成器)或者您犯了错误。
  • 爱在这个确切的时刻,问题和所选答案都有 128 分。巧合? ??????

标签: sql-server guid


【解决方案1】:

基本上没有。我想有人去弄乱你的数据库。根据您使用的版本 GUID,该值要么是唯一的(对于版本 1 GUID 之类的东西),要么是唯一且不可预测的(对于版本 4 GUID 之类的东西)。 SQL Server 对其 NEWID() 函数的实现似乎使用 128 位随机数,因此不会发生冲突。

对于 1% 的碰撞几率,您需要生成大约 2,600,000,000,000,000,000 GUID。

【讨论】:

  • 这就是我的想法,但我只是想确保我不能排除这种可能性。你永远不知道有 8 年历史的软件会出现什么样的奇怪错误。 :)
  • 其实这已经不是真的了。 v1 GUID 确实如此,但当前的 v4 GUID 则不然。请参阅en.wikipedia.org/wiki/Globally_Unique_Identifier#Algorithm 了解更多信息。
  • 投反对票,因为原则上(以最原始的形式),您对“是否可能发生 GUID 冲突?”的问题说“不”是错误的。这是很有可能的。这种可能性很小,但有可能。我讨厌听起来很迂腐 - 但 SO 就是要简洁准确。
  • 在 wolfram alpha 中输入 "solve[1-exp[-(n^2/(2*2^128))] > 0.01, n]" 得到 1% 的结果...请注意,虽然这个数字在 ONE 应用程序的上下文中看起来很大,但对于整个世界来说肯定不是很大。如果地球上的每台计算机都会生成真正的 GUID,那么它们将在大约一秒内以 1% 的概率发生碰撞,假设它们可以每纳秒生成一个 GUID(这在当今可能是相当现实的)。因此,如果您使用 GUID 作为数据库 ID,那么它们是唯一的。在地球上完成的每一次计算的 GUID 都会立即发生冲突。
  • 说“不”这是不可能的,然后说当产生一定数量时有 1% 的机会发生碰撞,是直接冲突。正确的响应应该是理论上的 - 是的,碰撞可能会随机发生。然而,从统计上讲,碰撞的几率比小行星撞击地球、从地球反弹并从月球反弹并在接下来的一个小时内第二次撞击地球的几率要小。
【解决方案2】:

基本上他们不可能!,机会是天文数字低

但是...我是我所知道的世界上唯一一个曾经患过 GUID 结肠炎的人(是的!)。

我很确定,这不是一个错误。

它是如何发生的,在 Pocket PC 上运行的小型应用程序中,在操作结束时必须发出具有生成的 GUID 的命令。在服务器上执行后的命令与执行日期一起存储在服务器上的命令表中。有一天,当我调试时,我发出了模块命令(附加了新生成的 GUID),但什么也没发生。我又做了一次(使用相同的 guid,因为 guid 在操作开始时只生成一次),又一次,什么也没有,最后试图找出命令没有执行的原因,我检查了命令表,并且与当前 GUID 相同的 GUID 是在 3 周前插入的。不相信这一点,我从 2 周的备份中恢复了一个数据库,并且 guid 就在那里。检查代码,毫无疑问,新的 guid 是新生成的。 Pow guid 碰撞,只发生过一次,但我真的希望我能在乐透中获胜,机会更大:)。

编辑:有一些因素可能会大大增加发生这种情况的机会,应用程序在 PocketPC 模拟器上运行,并且模拟器具有保存状态功能,这意味着每次状态都会恢复到本地时间也恢复了,guid 基于内部计时器....紧凑框架的 guid 生成算法可能不如 COM 的完整...

【讨论】:

  • 赞成。保存状态和重播确实会生成重复的 guid。
  • 可能发生的事情是这是一个“糟糕”的 GUID 实现。 理论上的几率非常低,但在 Pocket PC 上?谁能说他们没有走捷径,将这些几率提高到“不太可能,但可能”的类别。
  • 某事发生的概率很低并不意味着它不会发生。
  • 正如我在上面所说的那样,发生这种情况的可能性越来越小,以至于可以安全地假设您犯了错误或 MSSQL 使用了有缺陷的 PRNG (en.wikipedia.org/wiki/Pseudorandom_number_generator)。例如。这个 PRNG 很可能是用一个小尺寸的种子初始化的。有缺陷的 PRNG 并不罕见(参见 schneier.com/paper-prngs.html) - 例如,最近在 Android SDK 中发现了一个缺陷 - android-developers.blogspot.com/2013/08/… + usenix.org/conference/woot14/workshop-program/presentation/…
  • @Alex,错误是来自模拟器的“保存状态和恢复”,它恢复了整个模拟器映像,包括模拟器时钟。因此,在一年多的数千次恢复操作之后,产生了一次 guid 冲突。你是对的,有一个错误!
【解决方案3】:

它们在理论上是可能的,但是有 3.4E38 个可能的数字,如果您在一年内创建数万亿个 GUID,那么出现一个重复的机会是 0.00000000006 (Source)。

如果两个用户最终使用相同的 GUID,我敢打赌,程序中存在导致数据被复制或共享的错误。

【讨论】:

  • "但有 3.4E38 个可能的数字" - 没有。在同一台机器上几乎同时生成的两个 GUID 最终会得到极其相似的 GUID。
  • 这将取决于 GUID 的生成方式,并且一些基于 CPU 时间或毫秒的实现将(希望)夸大其基于的任何计算,因此相隔毫秒生成的两个 GUID 将具有巨大的区别。
  • 一台机器上有多个处理器,如果 guid 是基于时间和 mac 地址的,那么每个内核可以在同一时间发出相同的 guid。
  • 我很确定任何体面的 GUID 实现都不会
  • @MatthewLock 源代码中涵盖了生日悖论。检查链接。
【解决方案4】:

首先让我们看看两个 GUID 发生冲突的可能性。正如其他答案所述,由于birthday paradox,它不是 2 ^ 128 (10 ^ 38) 中的 1,这意味着两个 GUID 有 50% 的机会发生碰撞的概率实际上是 2 ^ 64 中的 1 (10 ^19) 这要小得多。但是,这仍然是一个非常大的数字,因此假设您使用合理数量的 GUID,发生冲突的可能性很低。

还要注意,GUID 不包含许多人似乎也相信的时间戳或 MAC 地址。 v1 GUID 确实如此,但 now v4 GUIDs are used, which are simply a pseudo-random number 这意味着碰撞的可能性可能更高,因为它们不再是时间和机器独有的。

所以基本上答案是肯定的,碰撞是可能的。但它们的可能性极小。

编辑:固定为 2^64

【讨论】:

  • 虽然我同意您的所有事实,但请注意您的数学。要说任何两个 GUID 发生冲突的概率为 10^19 中的 1,取决于集合中有多少 GUID。对于这个机会,您需要 ~2^32 个 GUID,因此在几乎所有真实世界的场景中,几率都要低得多。
  • 你有一个错字1 in 10^64 (10^19),我认为应该是1 in 2^64 (10^19)。我也很困惑您认为生日悖论仅适用于 2 个数字。我假设你看过en.wikipedia.org/wiki/Birthday_paradox。该表显示了对于给定的重复概率,您需要多少个 guid。从该表中,10^18 中 1 的概率需要 2.6 * 10^10 个 guid,而不是接近两个 GUID。
  • 一点——v1 guid 仍在广泛使用,并且依赖于 MAC 地址,特别是在数据库中,因为它们具有理想的特性。请参阅 UuidCreateSequential,它是 SQL Server 包装器 NewSequentialID (msdn.microsoft.com/en-us/library/windows/desktop/…)。
【解决方案5】:

两个随机 GUID 发生冲突的几率(10^38 中约 1 个)低于未检测到损坏的 TCP/IP 数据包的几率(10^10 中约 1 个)。 http://wwwse.inf.tu-dresden.de/data/courses/SE1/SE1-2004-lec12.pdf,第 11 页。磁盘驱动器、CD 驱动器等也是如此......

GUID 在统计上是唯一的,您从数据库中读取的数据仅在统计上是正确的。

【讨论】:

  • 你确定我不可能保护我的网络,因此每 10^28 个数据包中只有不到 1 个数据包损坏吗?
【解决方案6】:

在这种情况下,我认为Occam's razor 是一个很好的指南。您极不可能发生 GUID 冲突。很有可能您有错误,或者有人在弄乱您的数据。

【讨论】:

  • 其实在这种情况下,奥卡姆剃刀根本就不是一个好的指南!奥卡姆剃刀说假设最少的情况最有可能是正确的。在这种情况下,GUID 冲突的情况实际上要简单得多,但奥卡姆剃刀不适用于我们已经知道其中一种情况极不可能发生的情况。
【解决方案7】:

参见维基百科的Globally Unique Identifier 文章。有几种方法可以生成 GUID。显然,旧的(?)方式使用了 Mac 地址、一个非常短的单位的时间戳和一个唯一的计数器(用于管理同一台计算机上的快速生成),因此使它们重复几乎是不可能的。但是这些 GUID 被删除了,因为它们可以用来追踪用户...

我不确定 Microsoft 使用的新算法(文章说可以预测 GUID 序列,看起来他们不再使用时间戳?上面链接的 Microsoft 文章说别的......)。

现在,GUID 被精心设计为在名称上是全球唯一的,所以我敢冒险这是不可能的,或者概率非常非常低。我会去别处看看。

【解决方案8】:

你是数学家吗?那么是的。

你是工程师吗?然后没有。

【讨论】:

    【解决方案9】:

    具有重复 MAC 地址的以太网卡的两台 Win95 机器将在严格控制的条件下发出重复的 GUIDS,尤其是在建筑物中断电并且它们同时启动的情况下。

    【讨论】:

    • 两台不同的机器拥有相同的以太网 MAC 地址是否常见?
    • @DaveLucre:没有,但是已经记录了事件。
    • 我真的很好奇这是怎么回事。 VM 是否更有可能为每个 NIC 随机生成 MAC?我从未听说过使用重复 MAC 制造的物理 NIC!如果可能的话,有点像在工作中投入巨大的扳手!
    • 哇!感谢@Joshua 的链接!真是个大坏蛋!
    • @DaveLucre 我使用了一些非常便宜的 USB NIC,它们都是用相同的 MAC 制造的。但当然,这与随机性的数学无关,而与制造商的懒惰有关。
    【解决方案10】:

    我会以“我不是网络人,所以我可能会在后面写完全不连贯的句子。”作为开头。

    当我在伊利诺伊州立大学工作时,我们有两台戴尔台式机,订购时间不同。我们将第一个放在网络上,但是当我们尝试将第二个放在网络上时,我们开始收到疯狂的错误。经过多次故障排除后,确定两台机器都产生了相同的 GUID(我不确定究竟是为了什么,但它使它们都无法在网络上使用)。戴尔实际上将两台机器都替换为有缺陷的机器。

    【讨论】:

    • 它是专门的 GUID。这与机器加入网络时生成的 GUID 有关。戴尔花了数周时间更换机器,因为他们说 GUID 不可能相同。我们能够重现问题,戴尔收回机器,并能够在他们的网络上产生相同的结果。他们最终更换了两台机器。正如我所说,我不是网络人,但我特别记得这是 GUID 的问题。
    【解决方案11】:

    我知道人们喜欢 GUID 很神奇并且保证是唯一的,但实际上,大多数 GUID 只是 121 位随机数(其中 7 位浪费在格式化上)。如果您不习惯使用大随机数,那么您也不应该习惯使用 GUID。

    【讨论】:

    • 也建议不要使用网络。或者电脑。奇偶校验位只能做这么多!
    • 你误会了。我想在这篇文章中说两件事:1)如果您需要一个大随机数,请使用一个大随机数。使用 GUID 作为大随机数是不必要的误导。 (2)
    • 我完全清楚这一点。你说“如果你不习惯使用一个大的随机数。”但是 GUID 是如此独特,以至于您会发现计算机中的几乎所有其他内容都更加随机,甚至是您认为理所当然的操作。与(真正的)GUID 冲突相比,异常内存故障破坏您的身份列的可能性更大。你不应该对他们感到“不舒服”。如果它们不适合该场景,那很好 - 但它们不需要特别小心。
    • 我想这无济于事,但人们试图向您解释的是,常见硬件(如网卡或硬盘驱动器)中的错误检测机制使用的算法比您检测到错误的可能性更大获得 GUID 冲突,所以如果你依赖这些,你也可以依赖 GUID
    • @Rick,取决于你的号码有多大。绝对不是 4 字节 int 或 8 字节 bigint。 GUID=16 字节,因此您需要一个自定义的 16 字节大数字实现来实现相同的 2^128 个可能的组合。所以一般来说,如果使用“普通”int 或 bigint 随机数,与 GUID 发生冲突的几率会更低(忽略每个随机算法的考虑)。
    【解决方案12】:

    用于生成 GUID 的代码是否存在错误?是的,当然可以。但是答案与编译器错误的答案相同 - 您自己的代码更有可能出现错误,所以先看看那里。

    【讨论】:

      【解决方案13】:

      当然有可能....可能吗?不太可能,但有可能。

      请记住,同一台机器正在生成每个 GUID(服务器),因此很多基于机器特定信息的“随机性”都会丢失。

      【讨论】:

        【解决方案14】:

        广义公式

        有一个公式可以估计要生成多少个大小为 S 的值,以使它们中的两个以概率 P 发生碰撞。

        变量:

        • 位 - 您的数据类型中有多少位。
        • 概率 - 碰撞的目标概率。

        要发生碰撞,您必须生成周围:

        或者在 Python 中:

        from math import sqrt, log
        
        def how_many(bits, probability):
            return 2 ** ((bits + 1) / 2) * sqrt(-log(1 - probability))
        

        GUID

        对于 GUID(128 位),要以 1% (0.01) 的概率获得碰撞, 你需要:

        In [2]: how_many(bits=128, probability=0.01)
        Out[2]: 2.6153210405530885e+18
        

        ...大约 2.6 * 10^18 个 GUID(即 42 艾字节的 GUID)。

        请注意,此概率会迅速增长。与位数无关,对于 99.99% 的概率,您只需要比 1% 多 30 倍的 GUID!

        In [3]: how_many(bits=128, probability=0.9999)
        Out[3]: 7.91721721556706e+19
        

        Int64

        相同的数字,但对于 int64 数据类型:

        In [4]: how_many(bits=64, probability=0.01)
        Out[4]: 608926881
        
        In [5]: how_many(bits=64, probability=0.9999)
        Out[5]: 18433707802
        

        对于 1% 的冲突概率,您需要 5 GB 的 int64-s。仍然很多,但与 GUID 相比,这是一个更易于理解的数字。


        这就是所谓的birthday problem - 在这篇维基百科文章中,您可以找到比这更精确的估计公式。

        【讨论】:

          【解决方案15】:

          只是为了笑,试试下面的脚本...(适用于 SQL 2005,不确定 2000)

          declare @table table
          (
              column1 uniqueidentifier default (newid()),
              column2 int,
              column3 datetime default (getdate())
          )
          
          declare @counter int
          
          set @counter = 1
          
          while @counter <= 10000
          begin
              insert into @table (column2) values (@counter)
              set @counter = @counter + 1
          end
          
          select * from @table
          
          select * from @table t1 join @table t2 on t1.column1 = t2.column1 and t1.column2 != t2.column2
          

          重复运行(不到一秒)从第一次选择产生相当大的范围,即使时间间隔非常短。到目前为止,第二个选择还没有产生任何结果。

          【讨论】:

          • 您需要在计数器末尾再添加 15 个零才能有 50% 的机会重复。但是,看在皮特的份上,不要这样做!
          【解决方案16】:

          如果用户有不同的机器和网卡,这是不可能的,即使没有,这仍然是一个非常边缘的几乎理论上的风险。

          我个人会寻找其他地方,因为它更有可能是一个错误而不是 GUID 冲突......

          当然,前提是您不会从 GUID 上剪掉一些片段以使其更短。

          【讨论】:

          • GUID 将在服务器上生成,因此用户的网卡不会发挥作用。
          【解决方案17】:

          当然有可能,甚至可能。并不是每个 GUID 都在可能的数字空间的随机部分中。如果两个线程试图同时生成一个线程,除非某种集中的 GUID 函数带有信号量,否则它们最终可能会得到相同的值。

          【讨论】:

            【解决方案18】:

            如果您通过 SQL Server 中的 NEWID() 函数之类的东西生成 GUID 冲突,那么您极不可能遇到 GUID 冲突(尽管当然有可能,正如其他答案所强调的那样)。他们没有指出的一件事是,如果您在野外浏览器的 JavaScript 中生成 GUID,实际上很可能会遇到冲突。不仅在不同浏览器中的 RNG 有时会出现问题,而且我还遇到了 Google 蜘蛛似乎缓存类似函数结果的问题,并最终将相同的 GUID 反复传递给我们的系统。

            在此处查看各种答案以获取更多详细信息:

            Collisions when generating UUIDs in JavaScript?

            【讨论】:

              【解决方案19】:

              不要担心它是什么。让它成为不可能。将 GUID 的不可能性与顺序的不可能性混合在一起。只需将我想要的数据库顺序添加到 GUID 并调用它完成。您可能需要将数据类型从 GUID 更改为 String-ish,但它们在存储方面并没有那么不同。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2013-01-29
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-03-23
                • 2017-06-29
                相关资源
                最近更新 更多