GUID 冲突可能吗?

我正在研究 SQLServer2000中的一个数据库,它为每个使用它所绑定的应用程序的用户使用 GUID。不知何故,两个用户使用了相同的 GUID。我知道微软使用一种算法来生成一个随机的 GUID,它引起冲突的几率非常低,但是冲突还是可能的吗?

90778 次浏览

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

就个人而言,我会在其他地方寻找,因为它更可能是一个 bug 而不是 GUID 冲突..。

当然,前提是您不会为了缩短 GUID 而将其删除。

基本上没有。我觉得有人动了你的数据库。根据您使用的 GUID 版本的不同,该值可以是唯一的(对于版本1的 GUID) ,也可以是唯一的和不可预测的(对于版本4的 GUID)。SQLServer 针对其 NEWID ()函数的实现似乎使用了128位随机数,因此不会出现冲突。

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

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

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

参见维基百科的 全局唯一标识符文章。有几种方法可以生成 GUID。很明显,老(?)方式使用的 Mac 地址,时间戳下降到一个非常短的单位和一个唯一的计数器(管理同一台计算机上的快速代) ,所以使他们复制几乎是不可能的。但是这些 GUID 被删除了,因为它们可以用来跟踪用户..。

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

现在,GUID 被精心设计成,按名称,全球唯一的,所以我将冒险它是不可能的,或者概率非常非常低。我会去别的地方找。

它们在理论上是可能的,但是对于3.4 E38的可能数字,如果您在一年内创建了数十万亿个 GUID,那么出现一个重复的概率是0.00000000006(来源)。

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

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

我将以“我不是一个网络人士,所以我可能会造成完全语无伦次的句子”作为开场白。

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

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

但是... 我是这个世界上我唯一知道的人,那个 曾经有过一次 GUID 冲突(是的!)。

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

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

编辑: 有一些因素可能会大大增加这种情况发生的几率,应用程序运行在 PocketPC 仿真器,并且仿真器有一个保存状态的功能,这意味着每次状态恢复时,本地时间也恢复了,指南是基于内部计时器... 也指南生成算法为紧凑的框架可能不如例如 COM 一个完整的..。

用于生成 GUID 的代码中是否存在 bug?是的,当然可以。但是这个答案和编译器的 bug 是一样的——你自己的代码数量级更容易出错,所以先看看那里。

两个随机 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 在统计学上是唯一的,从数据库读取的数据仅在统计学上是正确的。

在这种情况下,我认为 Occam 剃刀是一个很好的指南。不太可能出现 GUID 冲突。更有可能的情况是,您有一个 bug,或者有人对您的数据进行了篡改。

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

还要注意,GUID 并不包含时间戳或 MAC 地址,许多人似乎也这样认为。这对于 v1 GUID 是正确的,但是 现在使用的是 v4 GUID,它只是一个伪随机数意味着碰撞的可能性更高,因为它们不再是一个时间和一台机器的唯一性。

所以基本上答案是肯定的,碰撞是可能的,但是几乎不可能。

编辑: 修改为说2 ^ 64

两台拥有带有重复 MAC 地址的以太网卡的 Win95计算机将在严格控制的情况下发出重复的 GUIDS,特别是,例如,如果大楼停电并且它们都在同一时间启动。

为了方便起见,请尝试下面的脚本... (适用于 SQL2005,不确定是否适用于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

重复运行这个选项(花费不到一秒钟)会产生与第一个选项相比较大的范围,即使时间间隔非常短。到目前为止,第二个选择没有产生任何东西。

我知道人们喜欢这个感觉不错的答案: GUID 是神奇的,并且保证是唯一的,但实际上,大多数 GUID 只是121位的随机数(其中7位浪费在格式化上)。如果使用一个大的随机数让您感觉不舒服,那么使用 GUID 也会让您感觉不舒服。

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

有关详细信息,请参阅这里的各种答案:

在 JavaScript 中生成 UUID 时的冲突?

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

你是工程师吗,那就不是。

广义公式

有一个公式可以用来估计产生多少个大小 S 的值来得到两个大小 S 之间的碰撞概率为 P。

变量:

  • Bit-数据类型中的位数。
  • 碰撞概率-目标概率。

为了得到碰撞,你必须产生:

2^{\frac{bits + 1}{2}} * \sqrt{-log_2(1 - probability)}

或者在 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 (GUID 的 42EB)。

请注意,这种可能性增长迅速。不管比特数多少,对于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% 的碰撞概率,你将需要 int64-s 的 5G。仍然很多,但与 GUID 相比,这是一个更容易理解的数字。


这就是所谓的 生日问题——在维基百科的这篇文章中,你可以找到比这个更精确的估算公式。

别管是什么。让它变得不可能。将 GUID 的不可能性与顺序的不可能性混合起来。只需要在 GUID 中添加一个数据库顺序,然后就可以完成了。您可能需要将数据类型从 GUID 更改为 String-ish,但它们在存储方面并没有那么大的不同。