142

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

4

19 回答 19

142

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

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

于 2008-10-08T21:00:41.027 回答
118

基本上他们是不可能的!, 几率是天文数字的低

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

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

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

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

于 2008-10-08T21:25:46.700 回答
37

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

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

于 2008-10-08T21:06:54.197 回答
22

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

另请注意,GUID 不包含许多人似乎也相信的时间戳或 MAC 地址。这对于 v1 GUID 是正确的,但现在使用 v4 GUID,它只是一个伪随机数,这意味着冲突的可能性可以说更高,因为它们不再是时间和机器独有的。

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

编辑:固定为 2^64

于 2008-10-08T23:21:49.883 回答
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 在统计上是唯一的,您从数据库中读取的数据仅在统计上是正确的。

于 2008-10-08T22:44:58.710 回答
13

在这种情况下,我认为奥卡姆剃刀是一个很好的指南。您极不可能发生 GUID 冲突。您更有可能遇到错误,或者有人在弄乱您的数据。

于 2008-10-08T23:05:50.710 回答
11

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

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

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

于 2008-10-08T21:06:42.730 回答
10

你是数学家吗?好的。

你是工程师吗?那就不要。

于 2020-09-12T17:56:33.553 回答
9

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

于 2008-10-16T04:25:01.317 回答
5

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

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

于 2008-10-08T21:16:56.860 回答
5

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

于 2010-10-27T07:40:38.517 回答
3

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

于 2008-10-08T21:36:14.637 回答
2

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

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

于 2008-10-08T21:06:23.917 回答
2

广义公式

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

变量:

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

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

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

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

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

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

整数64

相同的数字,但对于 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 相比,这是一个更易于理解的数字。


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

于 2021-03-29T10:30:41.140 回答
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

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

于 2008-10-31T15:02:09.267 回答
0

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

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

当然,前提是您不要从 GUID 上切掉一些位以使其更短。

于 2008-10-08T21:00:18.407 回答
0

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

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

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

于 2016-01-18T20:16:00.077 回答
0

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

于 2022-02-09T12:05:25.513 回答
-1

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

于 2008-10-08T21:11:00.880 回答