GUID碰撞可能吗?


128

我正在使用SQL Server 2000中的一个数据库,该数据库为每个使用与其绑定的应用程序的用户使用GUID。不知何故,两个用户最终获得了相同的GUID。我知道微软使用一种算法来生成随机GUID,该GUID引起碰撞的可能性极低,但是碰撞仍然可能吗?


11
所有人都说“不对”。我已经与1个UniqueIdentifier碰撞了少于一百万条记录的数据集,MSSQL 2008 R2
Behrooz

2
@贝鲁兹·依克斯 多亏了我们的朋友生日悖论,这并非不可能,但是对于完全随机的v4 GUID来说仍然是不幸的。也许您使用的是较弱的GUID生成策略?
克雷格·林格

6
@Behrooz哇。真是太幸运了。
Craig Ringer

6
@Behrooz,这可能是MSSQL中使用的有缺陷的伪随机数(如果考虑到其软件的质量,如果他们的生成器或类似物中包含32位种子,我不会感到惊讶)。数学不是骗人的。这种可能性很小,以至于您可能达到99.9999999999%(之后为9),以至于MSSQL guid生成器有缺陷(或者可能是用于生成GUID的伪随机生成器)或您犯了错误。
Alex

2
爱在这个确切的时刻,问题和所选答案都获得128分。巧合?🤔
卡欧库尼亚

Answers:


127

基本上没有 我认为有人在破坏您的数据库。根据所使用的GUID版本,该值是唯一的(对于版本1 GUID而言),或者是唯一且不可预测的(对于版本4 GUID而言)。SQL Server的NEWID()函数的实现似乎使用了128位随机数,因此不会发生冲突。

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


3
我就是这么想的,但是我只是想确保自己不能排除这一点。您永远不会知道在8年以上的软件中可能会弹出哪些奇怪的错误。:)
杰森·贝克

6
实际上,这不再是真的。对于v1 GUID确实如此,但对于当前的v4 GUID则不是。有关更多信息,请参见en.wikipedia.org/wiki/Globally_Unique_Identifier#Algorithm
格雷格·比奇

95
投反对票,因为原则上(以最原始的形式),您对“ GUID是否可能发生冲突?”的问题说“不”是错误的。这很有可能。可能性很小,但是有可能。我讨厌听起来很古怪-但是SO的全部目的就是简洁和准确。

13
在Wolfram alpha中输入“ solve [1-exp [-(n ^ 2 /(2 * 2 ^ 128))]> 0.01,n]”,以得到1%的结果...请注意,尽管这个数字看起来很大在一个应用程序的上下文中,对于整个世界来说,它当然并不大。如果地球上的每台计算机都能够生成真实的GUID,那么假设它们每纳秒就可以生成一个GUID,那么它们将在大约一秒钟内以1%的概率引起碰撞(这在当今很现实)。因此,如果您使用GUID作为数据库ID,则它们是唯一的。地球上进行的每一次计算的GUID都会立即发生冲突。
thesaint 2014年

11
说“不”是不可能的,然后说当发生一定数量的碰撞时,有1%的机会发生碰撞是直接冲突。正确的响应应该是理论上的-是的,可能会随机发生碰撞。然而,据统计,相撞的机会要比小行星撞击地球,在下一个小时内从地球弹起并从月球反弹并再次撞击地球要小。
巴勒斯

112

基本上不可能!天文机会很少

但是...我是我所认识的世界上唯一一个曾经有过GUID菌落的人(是!)。

我敢肯定,这不是一个错误。

在运行于Pocket PC上的小型应用程序中,在操作结束时,必须发出具有生成的GUID的命令,这是怎么发生的。在服务器上执行后的命令,连同执行日期一起存储在服务器上的命令表中。有一天,当我进行调试时,我发出了模块命令(附加了新生成的GUID),但没有任何反应。我又做了一次(使用相同的guid,因为guid在操作开始时只生成了一次),然后又一无所获,最终试图找出为什么命令未执行的原因,我检查了命令表, 3周前插入了与当前GUID相同的GUID。不相信这一点,我从2周的备份中恢复了数据库,并且guid在那里。检查代码,毫无疑问,新生成的新guid。

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


38
已投票。保存状态并重播确实会产生重复的引导。
约书亚

35
可能发生的是这是一个“不良” GUID实现。该理论的可能性是非常低的,但Pocket PC上?谁能说他们没有采取捷径将这些几率提高到“不太可能,但可能”类别中。
戴夫·多普森

9
仅仅因为某件事发生的可能性非常低并不意味着就不会发生。
Renan 2013年

3
就像我在上面说的那样,这种机会的可能性越来越小,可以肯定地假设您犯了一个错误或者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

2
@Alex,错误是来自仿真器的“保存状态并还原”,它可以还原整个仿真器映像,包括仿真器时钟。因此,在经过一年的数千次还原操作后,发生了一次Guid冲突。您说的没错!
Pop Catalin

34

从理论上讲,它们是可能的,但如果有3.4E38个可能的数字,则如果您一年内创建数十万亿的GUID,则重复的几率为0.00000000006(来源)。

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


“但有3.4E38个可能的数字”-不。几乎同时在同一台计算机上生成的两个GUID最终将具有极其相似的GUID。
柯克·斯特拉瑟

4
这将取决于GUID的生成方式,并且某些基于CPU时间或毫秒的实现(希望)会夸大其基于任何基于毫秒数生成的两个GUID的计算,而将产生巨大的差异。
大林Seivewright

4
如果一台计算机上有多个处理器,则如果Guid基于时间和mac地址,则每个内核可以在同一时间发布相同的Guid。
AndyM

12
我很确定任何体面的GUID实现都不会
Guillaume86

1
@MatthewLock来源中涵盖了生日悖论。检查链接。
Zero3 '16

21

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

还请注意,GUID不包含很多人似乎相信的时间戳或MAC地址。对于v1 GUID确实如此,但是现在使用v4 GUID,它只是一个伪随机数,这意味着发生碰撞的可能性可能更高,因为它们不再是时间和机器所独有的。

因此,基本上答案是肯定的,可能发生碰撞。但是它们极不可能。

编辑:固定说2 ^ 64


2
虽然我同意您的所有事实,但请注意数学。要说您有两个十分之一的GUID发生碰撞的机会是十分之一,这取决于集合中有多少个GUID。为此,您需要约2 ^ 32个GUID,因此在几乎所有实际场景中,几率都低得多。
DocMax

1
你有错字1 in 10^64 (10^19),我想应该是1 in 2^64 (10^19)。我也很困惑您如何认为生日悖论仅适用于2个数字。我假设您查看了en.wikipedia.org/wiki/Birthday_paradox。该表显示了给定的重复概率,您需要多少个向导。从该表中,十分之一为18 ^的概率需要2.6 * 10 ^ 10 guid,而不是仅与两个GUID接近的概率。
Tony Lee,

一点-v1指南仍在广泛使用,并且依赖于MAC地址,特别是在数据库中,因为它们具有理想的特性。请参阅UuidCreateSequential及其SQL Server包装NewSequentialID(msdn.microsoft.com/zh-cn/library/windows/desktop/…)。
EBarr 2014年

18

两个随机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个损坏吗?
约书亚

13

在这种情况下,我认为奥卡姆(Occam)的剃须刀是一个很好的指南。发生GUID冲突的可能性极低。您更有可能是一个错误,或有人弄乱了您的数据。


1
实际上,在这种情况下,Occam的剃刀根本不是一个很好的指南!奥卡姆的剃刀说,假设最少的情况是最正确的。在这种情况下,GUID碰撞的情况实际上要简单得多,但是Occam的Razor不适用于这种情况,因为我们已经知道其中一种情况极不可能发生。
锁木

11

参见Wikipedia的全球唯一标识符文章。有几种生成GUID的方法。显然,旧的(?)方式使用Mac地址,时间戳(单位短)和唯一的计数器(用于在同一台计算机上管理快速生成),因此几乎不可能复制它们。但是这些GUID被删除了,因为它们可以用来追踪用户...

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

现在,顾名思义,GUID经过精心设计,使其具有全球唯一性,因此,我将冒这种可能性,即可能性很小或非常非常低的风险。我会去别的地方。





9

两台具有具有重复MAC地址的以太网卡的Win95机器将在严格控制的条件下发出重复的GUIDS,例如,如果建筑物中的电源关闭并且它们都完全同时启动,则尤其如此。


两台不同的机器具有相同的以太网MAC地址是否很常见?
Dave Lucre

@DaveLucre:否,但已记录了事件。
约书亚

我真的很好奇这是怎么发生的。VM为每个NIC随机生成MAC的可能性更大吗?我从未听说过使用重复的MAC制造物理网卡!如果可能的话,可以在工作中投入巨大的扳手!
戴夫·卢克雷

哇!感谢链接@Joshua!多么大的麻烦!
Dave Lucre

@DaveLucre我使用了一些非常便宜的USB NIC,其中所有的NIC都使用相同的MAC制造。但是,当然,这与随机性数学无关,而与制造商的懒惰无关。
rudolfbyker

5

我将以“我不是网络人士,因此我可能在后面说完全不连贯的句子”作为开头。

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


3
特别是GUID。这与机器加入网络时生成的GUID有关。戴尔花了几周的时间来更换机器,因为他们说GUID不可能完全一样。我们能够重现该问题,戴尔收回了这些机器,并在其网络上产生了相同的结果。他们最终更换了两台机器。正如我所说,我不是网络专家,但我特别记得这是GUID的问题。
约翰·卡夫

5

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


11
还建议您不要使用网络。或电脑。奇偶校验位只能做很多事情!
Rushyo

你误会了。我想在这篇文章中说两件事:1)如果您需要一个大随机数,请使用一个大随机数。将GUID用作大随机数是不必要的误导。(2)
Rick Yorgason 2011年

4
我完全知道。您说“如果您不愿意使用大随机数”。但是GUID是如此独特,以至于您会发现计算机中的几乎所有其他东西都是随机的,甚至是您认为理所当然的操作。与(真实的)GUID冲突相比,异常的内存故障将有可能破坏您的标识列。您不应对它们感到“不舒服”。如果它们不是该方案的理想选择,那就很好-但不需要特别注意。
Rushyo

3
我想这无济于事,但是人们试图向您解释的是,常见硬件(例如网卡或硬盘驱动器)中的错误检测机制使用的算法比您遇到GUID冲突的机会更大,无法检测到错误,因此如果您依靠这些,也可以依靠GUID
Guillaume86,

1
@Rick,取决于您的电话号码。绝对不是4字节int或8字节bigint。GUID = 16个字节,因此您需要自定义16个字节的大数字实现以实现相同的2 ^ 128种可能的组合。因此,一般而言,如果使用“正常”的int或bigint随机数,则与GUID发生冲突的几率更低(无需考虑每个算法的随机算法)。
Wim Hollebrandse 2012年

3

用于生成GUID的代码中是否可能包含错误?是的,当然可以。但是答案与编译器错误的答案相同-您自己的代码更容易出现错误,因此请首先查看。


2

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

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


1

仅出于咧嘴笑,请尝试以下脚本...(适用于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

反复运行(耗时少于一秒钟)与第一次选择相比,即使在极短的时间间隔内也会产生相当大的范围。到目前为止,第二选择什么都没有产生。


1
您需要在计数器末尾再加上15个零,才能有50%的机会重复。但是,就皮特而言,不要这样做!
Jim Birchall

0

如果用户使用带有网卡的其他计算机,则不可能,即使不是,也几乎没有理论上的风险。

就我个人而言,我会去其他地方看看,因为它更有可能是错误而不是GUID冲突...

当然,请提供您不要砍掉GUID使其更短的功能。


GUID将在服务器上生成,因此用户的网卡将不起作用。
汤姆·里特

0

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


0

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

有关更多详细信息,请参见此处的各种答案:

在JavaScript中生成UUID时发生冲突?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.