为何5万个随机7位十六进制字符串未碰撞?生日问题相关疑问
UUID最后7位做主键的生日问题碰撞疑惑
你的生日问题计算没毛病
16^7等于268,435,456个可能值,用生日问题的近似公式计算:P(n) ≈ 1 - e^(-n²/(2*N))
当n=50000时,得出的碰撞概率确实是99.05%,这个理论推导完全正确。
测试代码10次全碰撞是正常现象
你的测试逻辑没问题:每次生成全新的随机UUID,取最后7位用HashSet实时检测重复。单次试验碰撞概率99%,10次都撞的概率是0.99^10≈90.4%,属于大概率事件,完全符合预期。
同事5万条无碰撞的几种合理原因
虽然理论上几乎必然碰撞,但还是存在几种说得通的解释:
- 极低概率的巧合:0.95%的无碰撞概率,相当于每105次尝试里可能出现1次,虽然少见,但并非不可能发生。
- 实际插入逻辑有隐藏细节:
- 同事的代码可能误用了版本1(时间戳+MAC地址型)UUID,而非版本4(纯随机型)——版本1的最后几位不是纯随机生成的,重复概率会远低于版本4。
- 数据库的唯一约束自动拦截了碰撞的插入请求,同事统计的是成功插入的5万条,而非尝试插入的总数(实际可能尝试插入了更多数据,碰撞的请求被数据库直接拒绝了)。
- 截取逻辑存在差异:比如同事是先去掉UUID字符串中的横杠,再截取最后7位?不过这种方式和你的截取逻辑熵值一致,不会影响碰撞概率;但如果是截取了UUID的其他段,可能会有差异,不过你已经核实过数据库,这个可能性较低。
实用建议
如果真想用截取UUID的方式做主键,别赌小概率运气:要么直接用完整UUID,要么多截取几位——比如截10位,16^10有1万亿个可能值,5万条数据的碰撞概率几乎为0。
内容的提问来源于stack exchange,提问作者Andrew Cheong
相关产品推荐
相关产品推荐

