与6位随机字母数字代码发生冲突的概率是多少?

时间:2011-09-29 00:15:05

标签: mysql perl hash probability alphanumeric

我使用以下perl代码生成随机字母数字字符串(仅限大写字母和数字),以用作MySQL数据库中记录的唯一标识符。该数据库可能会保持在1,000,000行以下,但绝对现实最大值约为3,000,000。我有2个记录具有相同随机码的危险机会,或者它可能发生的次数非常少吗?我对概率知之甚少(如果从这个问题的性质来看还不是很清楚)并且会喜欢某人的意见。

perl -le 'print map { ("A".."Z", 0..9)[rand 36] } 1..6'

6 个答案:

答案 0 :(得分:38)

由于Birthday Paradox,它比您想象的更可能。

有2,176,782,336个可能的代码,但即使只插入50,000行也存在相当高的碰撞机会。对于1,000,000行,几乎不可避免地会发生很多碰撞(我认为平均约为250)。

我运行了一些测试,这是我在第一次碰撞发生之前可以生成的代码数量:

  • 73366
  • 59307
  • 79297
  • 36909

随着代码数量的增加,碰撞将变得更加频繁。

这是我的测试代码(用Python编写):

>>> import random
>>> codes = set()
>>> while 1:
        code=''.join(random.choice('1234567890qwertyuiopasdfghjklzxcvbnm')for x in range(6))
        if code in codes: break
        codes.add(code)

>>> len(codes)
36909

答案 1 :(得分:10)

嗯,你有36 ** 6个可能的代码,大约是20亿。调用此 d 。使用找到here的公式,我们发现 n 代码的碰撞概率大约为

1 - ((d-1)/d)**(n*(n-1)/2)

对于超过50,000左右的任何n,这都非常高。

看起来像一个10个字符的代码的碰撞概率只有大约1/800。所以请选择10个或更多。

答案 2 :(得分:7)

基于http://en.wikipedia.org/wiki/Birthday_paradox#Approximation_of_number_of_people给出的等式,在将大约55,000条记录插入此大小的Universe后,有50%的机会遇到至少一次碰撞:

http://wolfr.am/niaHIF

尝试插入两到六倍的记录几乎肯定会导致碰撞。您需要非随机地分配代码,或使用更大的代码。

答案 3 :(得分:6)

如前所述,生日悖论很可能使这一事件发生。特别是,当问题被视为碰撞问题时,可以确定精确的近似值。设p(n; d)为至少两个数相同的概率,d为组合数,n为路径数。然后,我们可以证明p(n; d)大约等于:

1 - ((d-1)/d)^(n*(n-1)/2)

我们可以在R中轻松绘制这个:

> d = 2176782336
> n = 1:100000
> plot(n,1 - ((d-1)/d)^(n*(n-1)/2), type='l')

给出了

enter image description here

正如您所看到的,碰撞概率随着试验/行数的增加而迅速增加

答案 4 :(得分:1)

虽然我不知道您想要如何使用这些伪随机ID的具体细节,但您可能需要考虑生成3000000个整数的数组(从1到3000000)并随机混洗它。这将保证数字是唯一的。 请参阅Fisher-Yates shuffle on Wikipedia

答案 5 :(得分:0)

注意事项:谨防依赖伪随机数生成器质量重要的内置rand。我最近发现了Math::Random::MT::Auto

  

Mersenne Twister是一种快速伪随机数发生器(PRNG),能够向可能耗尽“真正”随机数据源或系统的应用程序提供大量(> 10 ^ 6004)的“高质量”伪随机数据 - 提供的PRNG,例如rand

该模块为rand提供了替代方案,方便使用。

您可以使用以下代码生成密钥序列:

#!/usr/bin/env perl

use warnings; use strict;
use Math::Random::MT::Auto qw( rand );

my $SEQUENCE_LENGTH = 1_000_000;
my %dict;
my $picks;

for my $i (1 .. $SEQUENCE_LENGTH) {
    my $pick = pick_one();
    $picks += 1;

    redo if exists $dict{ $pick };

    $dict{ $pick } = undef;
}

printf "Generated %d keys with %d picks\n", scalar keys %dict, $picks;

sub pick_one {
    join '', map { ("A".."Z", 0..9)[rand 36] } 1..6;
}

前段时间,我写过关于limited range of built-in rand on Windows的文章。您可能不在Windows上,但您的系统可能存在其他限制或陷阱。