Générer un grand nombre de codes randoms uniques

J'ai un projet où nous aurons besoin de générer beaucoup de codes randoms de longueur fixe (Read: Millions) à partir d'un set de caractères (par exemple: alphanumérique à 12 numbers ou alphanumérique à 9 numbers seulement sans le caractère l). Nous allons ensuite stocker ces codes dans une database MSSQL (SQL Server 2008). La langue que nous utilisons est C #.

Nous devons également être en mesure de générer plus de codes et de les append à un set de codes existant, étant donné qu'ils sont uniques par rapport à eux-mêmes et aux codes existants. La quantité de codes randoms générés variera probablement de millions à seulement quelques centaines.

Les deux approches qui viennent à l'esprit sont soit de générer des codes et de les jeter à la database en saisissant des exceptions de contraintes uniques, soit de les déplacer localement dans une table de hachage puis de les calculer localement et de les placer dans la database .

Quelqu'un a-t-il une idée de laquelle des solutions ci-dessus serait la plus optimale ou encore mieux une autre solution plus efficace à laquelle je n'ai pas pensé?

Clarifications

Les codes générés doivent être non prévisibles et il y aura plusieurs lots, chacun avec un caractère unique en soi (par exemple: nous aurions le code A avec 100000 codes uniques, le code B avec 100000 codes uniques, mais il y aurait pas de ressortingction que A recoupe B est vide). Ils doivent également être faciles à utiliser pour un humain (d'où la courte longueur et les jeux de caractères potentiellement restreints pour éviter les caractères ambigus).

Les codes seront envoyés aux users par différentes methods (Email, SMS, imprimé sur papier, etc.) et seront utilisés plus tard (si quelqu'un devine le code de quelqu'un d'autre, ce serait mauvais).

Avez-vous envisagé d'utiliser des GUID (identifiants uniques dans SQL Server)? Ils sont uniques et la plupart du time randoms. Vous pouvez les générer sur le client ou sur le server.

Vous pouvez également envisager d'utiliser une fonction CLR du côté SQL pour réduire le nombre d'allers-returns DB.

Pour assurer l'unicité, une approche consiste à append un nombre unique et non random (tel que la valeur d'une colonne d'identité) à vos nombres randoms. Le résultat n'est pas random au niveau du bit par bit, mais il est random lorsqu'il est pris dans son set.

Générer des millions de nombres randoms uniques ne prendra pas longtime. Les insert dans la BD sera la partie la plus lente …

Cela dépend vraiment des exigences du problème spécifique. Les codes doivent-ils être uniques ou imprévisibles? Si elles doivent juste être uniques, alors vous pouvez utiliser un générateur de nombres randoms congruents linéaires pour créer vos codes.

Page Wikipedia sur les générateurs congruents linéaires

Voici un exemple de code:

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 Ssortingng 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); SsortingngBuilder builder = new SsortingngBuilder("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.ToSsortingng(); } private long _value = 0; } 

La class générera une séquence de 2 ^ 44 codes avant de la répéter (plus de 17 sortingllions de codes). Pour reprendre la séquence, il suffit d'save la valeur Seed actuelle et de la restaurer lorsque vous avez besoin de plus de codes.

Générer tous? Dans votre premier cas, vous avez un total de 35 caractères par position. Le stockage total est (base ^ positions) – 1 donc votre nombre total de combinaisons sur le bas est 36 ^ 9 – 1 ou 101,559,956,668,415 qui est presque un TB si les codes sont longs d'un octet … ce qu'ils ne sont pas. Et c'est au bas de l'échelle.

Le meilleur système consiste à pré-générer des lots de nombres valides et à les introduire dans les insertions. Si la méthode de génération est semi-random, vous pouvez le faire facilement en divisant les espaces randoms en utilisant des segments du tableau de bits. Mais vous ne mentionnez pas comment random est random.

Bien sûr, si vous avez un contrôle complet sur le caractère random, vous pouvez simplement utiliser les UUID, ce que nous faisons.

Pour générer des valeurs randoms hautement imprévisibles, puis-je suggérer d'utiliser la class System.Security.Cryptography.RNGCryptoServiceProvider.

Exemple de code pour générer des strings de longueur random de caractères randoms à partir d'un set prédéfini illustré ci-dessous. Cela a été utilisé dans un générateur de mot de passe.

 private ssortingng 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); ssortingng 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; }