生成大量唯一的随机码

时间:2009-11-24 00:42:25

标签: c# .net sql-server sql-server-2008

我有一个项目,我们需要从一组字符生成大量固定长度的随机代码(读取:数百万)(EG:12位字母数字或9位数字字母数字 - 只有没有l字符的情况)。然后我们将这些代码存储在MSSQL数据库(SQL Server 2008)中。我们使用的语言是C#。

我们还需要能够生成更多代码并将它们添加到现有代码集中,并且这些代码对自己和现有代码都是唯一的。生成的随机代码数量可能从数百万到数百不等。

要想到的两个明显的方法是生成代码并将它们抛出到数据库中捕获唯一约束异常,或者将数据本地下拉到哈希表中,然后在本地计算所有新代码并将它们放入数据库一旦生成。

有没有人知道上述哪种解决方案会更优化,哪种解决方案更有效率呢?

澄清

生成的代码必须是不可预测的,并且会有多个批次,每个批次都有自己的唯一性(EG:我们的代码集A包含100000个唯一代码,代码集B包含100000个唯一代码,但是'A相交B为空是没有限制的)。它们也必须易于人类使用(因此短的长度和可能受限的字符集以避免模糊的字符)。

代码将通过各种方法(电子邮件,短信,打印在纸上等)发送给用户,并在以后以一次使用方式使用(因此,如果有人猜到其他人的代码那就不好了)。< / p>

4 个答案:

答案 0 :(得分:4)

这实际上取决于具体的问题要求。代码必须是唯一的还是不可预测的?如果它们必须是唯一的,那么您可以使用线性同余随机数生成器来创建代码。

Wikipedia Page on Linear Congruential Generators

以下是一些示例代码:

class CodeGenerator
{
    public long Seed
    {
        get { return _value; }
        set { _value = value; }
    }

    private char[] alphabet =
        {
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
            'k', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
            'v', 'w'
        };

    public String GetCode()
    {
        // Generate the next value in the psuedo-random sequence.
        _value = (362881L * _value + 76552897L) & 0xFFFFFFFFFFFL;

        // Create the code.  Add 2^44 to avoid small codes.
        long code = _value + (1L << 44);

        StringBuilder builder = new StringBuilder("123456789");

        // The codes are all less than 2^45, so we have 45 bits of
        // information and need 9 digits.
        for (int i = 8; i >= 0; i--)
        {
            builder[i] = alphabet[code & 0x1F];
            code = code >> 5;
        }

        return builder.ToString();
    }

    private long _value = 0;
}

该类将在重复之前生成一系列2 ^ 44个代码(超过17万亿个代码)。要恢复序列,只需记录当前的种子值,并在需要更多代码时将其恢复。

答案 1 :(得分:4)

您是否考虑过使用GUID(SQL Server中的uniqueidentifier)?它们是独特的,大多是随机的。您可以在客户端或服务器上生成它们。

您可能还会考虑在SQL端使用CLR功能,以帮助最大限度地减少数据库往返次数。

为了确保唯一性,一种方法是在随机数中附加唯一的非随机数(例如标识列的值)。结果在逐位级别上不是随机的,但从整体上看它是随机的。

生成数百万个独特的随机数不会花费很长时间。将它们插入数据库将是一个缓慢的部分....

答案 2 :(得分:0)

生成所有这些?在第一种情况下,每个位置总共有35个字符。总存储量是(基数^位置) - 1所以你的低端组合总数是36 ^ 9 - 1或101,559,956,668,415,如果代码是一个字节长,那么它几乎是TB ......它们不是。那是低端的。

最好的系统是预先生成批次的有效数字并将这些数字输入到插入中。如果生成方法是半随机的,那么您可以通过使用位数组的段划分随机空间来轻松完成此操作。但是你没有提到随机是随机的。

当然,如果您完全控制随机性,那么您可以使用UUID,这就是我们的工作。

答案 3 :(得分:0)

为了生成高度不可预测的随机值,我建议您使用System.Security.Cryptography.RNGCryptoServiceProvider类。

用于从下面显示的预定义集合生成随机字符的abitrary长度字符串的示例代码。这已用于密码生成器。

private string GetRandomAlphanumericCharacters(int length)
{
    // Note: i, o, l, 0, and 1 have been removed to reduce 
    // chances of user typos and mis-communication of passwords.
    char[] allowedCharacters = { 'a', 'A', 'b', 'B', 'c', 'C', 'd', 'D', 'e', 'E', 'f', 'F', 'g', 'G', 'h', 'H', /*'i', 'I',*/ 'j', 'J', 'k', 'K', /*'l', 'L',*/ 'm', 'M', 'n', 'N', /*'o', 'O',*/ 'p', 'P', 'q', 'Q', 'r', 'R', 's', 'S', 't', 'T', 'u', 'U', 'v', 'V', 'w', 'W', 'x', 'X', 'y', 'Y', 'z', 'Z', /*'0', '1',*/ '2', '3', '4', '5', '6', '7', '8', '9' };

    // Create a byte array to hold the random bytes.
    byte[] randomNumber = new byte[length];

    // Create a new instance of the RNGCryptoServiceProvider.
    RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider();

    // Fill the array with a random value.
    Gen.GetBytes(randomNumber);

    string result = "";

    foreach (byte b in randomNumber)
    {
        // Convert the byte to an integer value to make the modulus operation easier.
        int rand = Convert.ToInt32(b);

        // Return the random number mod'ed.
        // This yeilds a possible value for each character in the allowable range.
        int value = rand % allowedCharacters.Length;

        char thisChar = allowedCharacters[value];

        result += thisChar;
    }

    return result;
}