首先声明,“我不是网络工程师,因此我可能会说出完全不连贯的句子。”
在伊利诺伊州立大学工作时,我们有两台戴尔台式电脑,分别在不同的时间订购。我们将第一台连接到了网络上,但当我们尝试将第二台连接到网络时,我们开始收到一些奇怪的错误信息。经过长时间的故障排除发现,两台机器都生成了相同的GUID(我不确定确切的用途,但它使它们无法在网络上使用)。最终,Dell公司替换了这两台电脑。
有一个公式可以估算生成大小为S的值,以使得两个值之间发生碰撞的概率为P。
变量:
要发生碰撞,你需要生成约:
或者在Python中:
from math import sqrt, log
def how_many(bits, probability):
return 2 ** ((bits + 1) / 2) * sqrt(-log(1 - probability))
对于长度为128位的GUID来说,要使碰撞概率达到1%(0.01),需要:
In [2]: how_many(bits=128, probability=0.01)
Out[2]: 2.6153210405530885e+18
… 大约有 2.6 x 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数据类型:
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%的碰撞概率,你需要5GB的int64-s。虽然仍然很多,但与GUID相比,这是一个更容易理解的数字。
这就是所谓的生日悖论问题 - 在这篇维基百科文章中,你可以找到比这更精确的估算公式。
生成GUID的代码可能存在漏洞吗?当然可能。但是,与编译器的错误一样,你自己的代码更有可能存在错误,因此首先要检查自己的代码。
当然这是可能的……但很不可能发生。
请记住,同一台机器生成每个GUID(服务器),因此基于特定机器信息的“随机性”大部分都会丢失。
只是为了好玩,试试下面的脚本...(适用于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
重复运行此操作(少于一秒钟)会从第一个选择中产生相当广泛的范围,即使时间间隔极短。到目前为止,第二个选择还没有产生任何结果。
如果您是通过 SQL Server 中的 NEWID()
函数生成 GUID,那么遇到 GUID 冲突的可能性非常小(当然,其他答案已经强调了这一点,但仍有可能发生)。他们没有指出的一件事是,如果您在浏览器中使用 JavaScript 生成 GUID,则很可能会遇到冲突。不仅不同浏览器中的 RNG 有时存在问题,而且我还遇到过 Google 爬虫似乎缓存了此类函数的结果,并且反复将相同的 GUID 传递给我们的系统。
有关更多详细信息,请参见此处的各种答案:
如果用户使用不同的机器和网络卡,那么这是不可能的,即使没有也只是极其边缘的理论风险。
个人认为更有可能是一个错误而不是GUID冲突,建议您在其他地方寻找解决方案...
当然,前提是您不会截断GUID以使其变短。
不要担心它是什么。让它变得不可能。将GUID的不可信性与顺序的不可能性混合在一起。只需将数据库顺序ID添加到GUID中,然后称之为完成。您可能需要将数据类型从GUID更改为类似字符串的类型,但在存储方面它们并没有太大的区别。
当然是可能的,甚至可能性很高。这并不像每个GUID都在可能的数字空间的随机部分中一样。如果两个线程同时尝试生成一个GUID,在没有某种带有信号量的集中式GUID函数的情况下,它们可能会得到相同的值。