11
votes

Un bon algorithme pour générer un numéro de commande

Autant que j'aime utiliser les GUID comme identifiant unique de mon système, il n'est pas très convivial pour les champs tels qu'un numéro de commande où un client peut avoir à répéter à un représentant du service à la clientèle.

Qu'est-ce qu'un bon algorithme à utiliser pour générer un numéro de commande afin qu'il soit:

  • unique
  • pas séquentiel (purement pour l'optique)
  • valeurs numériques uniquement (il peut donc être facilement lu sur un CSR par téléphone ou sur le téléphone)
  • <10 chiffres
  • peut être généré dans le niveau moyen sans faire un aller-retour dans la base de données.

    mise à jour (12/05/2009) Après avoir examiné attentivement chacune des réponses publiées, nous avons décidé de randomiser un numéro à 9 chiffres dans le niveau moyen d'être enregistré dans la DB. Dans le cas d'une collision, nous régénérerons un nouveau numéro.


5 commentaires

Connexes: Stackoverflow.com/questions/721497/...


Question naïve: Pourquoi pas séquentiel? Qu'est-ce que ça vous achète?


@Mathias - Je ne veux pas que nos concurrents sachent combien de commandes que j'ai achevées dans une période donnée.


@JOHN - La réponse acceptée dans la question que vous avez référencée est exactement ce que je ne veux pas faire ce que vous devez compter sur la base de données en tant que disjoncteur.


@Jason - Pourquoi ne ferez-vous pas ce que les gouvernements font avec les ID des citoyens: augmentez le comptoir mondial avec une quantité aléatoire de temps à autre.


10 Réponses :


9
votes

Si le niveau moyen ne peut pas vérifier quels "numéros de commande" existe déjà dans la base de données, le meilleur qu'il peut faire sera l'équivalent de générer un nombre aléatoire. Toutefois, si vous générez un nombre aléatoire qui est contraint d'être inférieur à 1 milliard, vous devriez commencer à vous inquiéter des collisions accidentelles à environ SQRT (1 milliard) , à savoir, après quelques dizaines de milliers d'entrées générées. WAY, le risque de collision est matériel. Et si le numéro de commande est séquentiel mais de manière déguisée, c'est-à-dire le prochain multiple de certains grands nombres premiers modulo 1 milliard - cela répondrait à vos exigences?


2 commentaires

+1 Il s'agit d'un générateur de nombres aléatoires congruentiels linéaires. Notez que la séquence peut être déduite de quelques numéros, il est uniquement obscurci.


Vous ne pouvez pas vraiment déduire une séquence s'il y a une possibilité réelle de vous manquer de chiffres. Par exemple. "1? 2? 4" pourrait très bien être séquentiel.



1
votes

Peut-être que vous pourriez essayer de générer un texte unique à l'aide d'une chaîne de Markov - voir ici pour un exemple de mise en œuvre en python. Peut-être utiliser des nombres séquentiels (plutôt que des aléatoires) pour générer la chaîne, de sorte que (espérons-le) que chaque numéro de commande est unique.

juste un avertissement, cependant - voir ici pour ce qui peut peut-être arriver si vous ne faites pas attention à vos paramètres.


0 commentaires

1
votes

Une solution serait de prendre le hachage de certains champs de la commande. Cela ne garantira pas qu'il est unique des numéros de commande de toutes les autres commandes, mais le risque d'une collision est très faible. J'imagine que sans "faire un aller-retour dans la base de données", il serait difficile de s'assurer que le numéro de commande est unique.

Si vous n'êtes pas familier avec les fonctions de hachage, la page Wikipedia est plutôt bonne.


1 commentaires

"Très faible" est optimiste: avec seulement 1 milliard de résultats possibles, les chances d'au moins une collision pour 60 000 commandes sont supérieures à 16%. CFR La Cast comme une collision paragraphe dans en.wikipedia.org/wiki/birthday_paradox : probabilité d'aucune collision en n ordres (avec le meilleur hachage possible: une aussi bonne que parfaite aléatoire!) est sur exp (-n * (n-1) / (2.0 * 10e9) / (2.0 * 10e9) / (2.0 * 10e9) / (2.0 * 10e9) / (2.0 * 10e9) / (2.0 * 10e9) / (2.0 * 10e9) / (2.0 * 10e9) / (2.0 * 10e9) / (2.0 * 10e9) / (2.0 * 10e9) / (2.0 * 10e9)) / code>.



1
votes

Vous pourriez baser64-coder un guid. Cela répondra à tous vos critères, à l'exception des besoins «Valeurs numériques uniquement».

Vraiment, cependant, la chose correcte est laissée à la base de données générer le numéro de commande. Cela peut signifier créer une commande dossier qui ne dispose pas d'un numéro de commande tant que l'utilisateur l'enregistre, ni d'ajouter la possibilité de créer vide (mais peut-être Commandes non engagées.


1 commentaires

Au cas où n'importe qui est intéressé, voici un article sur la base de base64-coder A GUID: CODINGHORREROR. com / blog / archives / 000409.html



0
votes

La réponse directe à la plupart de vos points de balle:

Faites de six premiers chiffres un champ augmentant séquentiellement et appendez trois chiffres de hachage à la fin. Ou sept et deux, ou huit et une, selon le nombre de commandes que vous envisagez de devoir prendre en charge.

Cependant, vous devrez toujours appeler une fonction sur le back-end pour réserver un nouveau numéro de commande; Sinon, il est impossible de garantir une non-collision, car il y a si peu de chiffres.


0 commentaires

1
votes

Utilisez des polynômes primitifs comme générateur de champ fini.


0 commentaires

5
votes

ok sonne comme un cas classique d'optimisation prématurée. Vous imaginez un problème de performance (oh mon Dieu, je dois accéder à la base de données - Horror - une base de données pour obtenir un numéro de commande! Mon qui pourrait être lent) et finir avec un gâchis compliqué de générateurs aléatoires Psuedo et une tonne de code de manutention en double. < / gémit>

Une réponse pratique simple consiste à exécuter une séquence par client. Le numéro de commande réel étant composite de numéro de client et de numéro de commande. Vous pouvez facilement récupérer la dernière séquence utilisée lors de la récupération d'autres éléments de votre client.


5 commentaires

+1. Vrai. Nous utilisons la séquence par approche client. Ça marche parfaitement sans faille. Vous avez moins de code à vous inquiéter. :)


@James: Ce n'est pas que nous avons peur d'accéder à la base de données - Gasp-Base de données. C'est parce que vous pouvez avoir une condition de course entre 2 commandes étant attribuée au même numéro de commande si vous allez dans la base de données et revenez au niveau moyen pour connaître le prochain numéro de commande logique.


Tableau avec une colonne 1 rangée 1. 1 Commande augmente et renvoie le résultat. Tout passe par la commande. Pas de soucis à propos d'une course.


La plupart des DBMSES SUPTE SUPORT Une «séquence» et la plupart des DBMSES prennent également en charge les sous-transactions ou les unités de travail de Spearate. Obtenez juste votre séquence suivante en dehors de l'UOW normale - vous vous retrouverez avec des lacunes dans la séquence de la séquence de l'annulation d'Uows annulée, etc. Mais cela n'a pas vraiment d'importance. Vous n'aurez certainement pas de conditions de course.


@James Anderson Je suis d'accord, je suis en désaccord. Si le client n'existe pas encore (nouvelle inscription), l'ensemble de l'ensemble de la création de l'utilisateur / de la commande de commande / de la carte de crédit / de la carte de crédit doit être enveloppé dans un bloc de transaction DB (puisque vous devez créer un utilisateur pour obtenir l'ID utilisateur et obtenir ensuite ID de la table des commandes). L'avantage de générer un GUID ou un équivalent est que, à l'avant, vous avez un identifiant unique à passer au processeur de paiement. Si le paiement réussit, alors, à ce stade, vous persistez à l'utilisateur / à la commande de DB dans une transaction à la restauration. Beaucoup de mise en œuvre plus propre, imo. Des compromis de toute façon, mais je préfère les GUDS



0
votes

Nous faisons TTT-CCCCCC-1A-N1.

  • T = Type de circuit (D1E = DS1 EEL, D1U = DS1 UNE, etc.)
  • C = ID client à 6 chiffres
  • 1 = premier emplacement du client
  • a = le premier circuit (A = 1, B = 2, etc.) à cet endroit
  • n = type de commande (n = nouveau, x = déconnecter, etc.)
  • 1 = le premier ordre de ce type pour ce circuit

2 commentaires

Bien que ce qui se passe sur ...- x10 ? ^^


Eh bien, la structure jette une erreur d'argument, mais en réalité, nous abandonnerions probablement après 9 tentatives infructueuses lors de la déconnexion d'un circuit et de prendre des ciseaux.



4
votes

Une option simple consiste à utiliser la date et l'heure, par exemple. 0912012359, et si deux commandes sont reçues dans la même minute, incrémentez simplement le deuxième ordre d'une minute (peu importe si le temps est sorti, c'est juste un numéro de commande).

Si vous ne voulez pas que la date soit visible, alors calculez-le comme le nombre de minutes puisqu'un point fixe à temps, par exemple. Lorsque vous avez commencé à prendre des commandes ou à une autre date arbitative. Encore une fois, avec le chèque / incrémentation en double.

Vos concurrents ne glanent rien de cela, et il est facile à mettre en œuvre.


1 commentaires

Pour augmenter la granularité, vous pouvez ajouter des secondes et des millisecondes. Mais vous rencontrerez toujours des conditions de course si vous n'avez pas d'usine de numéro de commande synchronisée.



1
votes

Votre exigence à 10 chiffres est une limite énorme. Considérez une approche en deux étapes.

  1. Utilisez un GUID
  2. Préfixe le GUID avec un hachage de 10 chiffres (ou 5 ou 4 chiffres) du GUID.

    Vous aurez plusieurs hits sur la valeur hachage. Mais pas que beaucoup. Les personnes du service clientèle seront très facilement capables de déterminer quel ordre est en question basé sur des informations supplémentaires du client.


0 commentaires