我遇到了一些生成多个UUID的代码,使用UUID.randomUUID()
,取每个UUID的最后7位数字(最近的UUID版本在熵方面是均匀分布的),并将其用作插入行到数据库中的键。
我想知道碰撞的概率是多少。我记得生日问题。这就是那个问题的一个实例,不是吗?一年有365天,而这里有16^7个可能的字符串。根据维基百科上的说法,给定n个字符串的碰撞概率为
其中d为16的7次方。
一位同事声称他们能够无问题地插入50000行数据。我对此表示怀疑,因为在n=50000和d=16的7次方条件下发生碰撞的概率是
1-((16^7-1)/16^7)^(50000*(50000-1)/2) = 99.05%
但是后来我检查了我们的数据库。确实有50,000个插入成功了。
这怎么可能呢?(除了他们真的很幸运之外。)我是不是误用了生日悖论?
编辑
这是一个最简化的测试,展示了该程序本应该会有碰撞。
import java.util.UUID;
import java.util.HashSet;
public class MyClass {
public static void main(String args[]) {
final int N = 50000;
for (int trial = 0; trial < 10; trial++) {
HashSet<String> strings = new HashSet<>();
Boolean success = true;
for (int i = 0; i < N; i++) {
String uuid = UUID.randomUUID().toString();
String id = uuid.substring(uuid.length() - 7);
if (strings.contains(id)) {
success = false;
// System.out.println(id);
break;
}
strings.add(id);
}
System.out.println(success);
}
}
}
对于N=50,000,10次尝试中有10次发生冲突-这符合99%的冲突率的预期。对于N=10,000,我看到0、1、2或3次尝试中出现冲突,这都在17%的冲突率的范围内,符合预期。
UUID.randomUUID()
来生成 50,000 个7位数字 ID。每次运行这个程序时,你是否会发现99%的冲突?也许在UUID.randomUUID()
背后的伪随机数生成器在某种程度上扭曲了概率。 - Scotty Jamisonfrom uuid import uuid4; [len({uuid4().hex[:7] for i in range(50000)}) for i in range(100)]
。我在200次尝试中得到了一个无冲突的集合。 - BoppreH