Création d'une clé primaire secondaire dans une base de données pour certaines tables

22

À certaines de mes tables, je veux ajouter "second_primary_key" qui sera uuid ou une clé longue aléatoire. J'en ai besoin car pour certaines tables je ne veux pas exposer des entiers à mon application web. Autrement dit, sur une page "/ factures", j'ai une liste de factures et un lien vers "/ factures /: id" où: id est un entier. Je ne veux pas qu'un utilisateur sache combien de factures dans mon système là-bas, donc au lieu de "/ factures / 123", je veux utiliser sa "seconde_primaire_clée" pour que l'URL soit "/ factures / N_8Zk241vNa"

Il en va de même pour les autres tables où je veux masquer un vrai identifiant.

Je me demande, est-ce une pratique courante? Quelle est la meilleure façon de mettre cela en œuvre?

Et comment s'appelle cette technique après tout, pour que je fasse une recherche dessus?

Dari
la source
20
Pourquoi ne pas se débarrasser complètement de l'entier?
larsbe
4
Vous pouvez définir autant de clés / index uniques que vous le souhaitez sur une table.
abuzittin gillifirca
2
Vous devriez peut-être appeler cela une clé candidate secondaire. "Primaire" n'en suggère qu'une.
Walter Mitty
4
"Deuxième primaire" est un oxymore. Vous avez une clé primaire et vous pouvez avoir des clés secondaires.
Arrêtez de nuire à Monica
7
@RobbieDee il existe des raisons valables de ne pas avoir une base de données entièrement normalisée. Et avoir un candidat ou une clé secondaire n'est pas exactement la duplication de données.
Machado

Réponses:

0

Vous pouvez ajouter une colonne UUID mais vous n'en avez vraiment pas besoin (et ne devriez pas). Il s'agit d'un problème de couche de présentation. Vous ne rêveriez pas de dire, en stockant une valeur monétaire de 1999 $ ainsi que 1999.

Vous voulez juste un moyen de masquer la valeur à la volée pour l'application. Vous pouvez le faire dans l'application elle-même ou en tant que vue de base de données.

Comme nous ne parlons que d'une seule valeur, regardez peut-être le cryptage bidirectionnel tel que AES ou similaire - le plus léger est le mieux.

Le hachage pourrait être une autre possibilité - cela dépend si vous souhaitez récupérer le numéro de facture, car le hachage est un moyen.

Robbie Dee
la source
48

Avoir une «clé primaire alternative» est un concept bien connu dans la modélisation de bases de données relationnelles, il est appelé «clé alternative», ou parfois aussi «clé secondaire». L'ensemble des "clés primaires potentielles" est appelé "clés candidates". Voir https://beginnersbook.com/2015/04/alternate-key-in-dbms/

La façon dont vous implémentez cela dépend entièrement de vous, surtout si vous souhaitez masquer le nombre total d'enregistrements. Il n'y a pas de "meilleur moyen", vous devez vérifier vos exigences comme le jeu de caractères autorisé ou utile, la longueur maximale, si vous voulez que les ID soient sensibles à la casse ou non, si vous voulez qu'ils soient lisibles sur une facture imprimée, si quelqu'un doit pouvoir les répéter au téléphone sans erreur, etc.

Doc Brown
la source
11
J'ai également vu les termes clé naturelle contre clé de substitution utilisés pour décrire ce scénario.
DanK
2
@Dari: vous avez demandé "comment s'appelle cette technique" - en gras. Et si le décryptage AES - peut-être à la volée - produit des clés du type que vous recherchez, utilisez-le, cela ne contredit pas ma réponse.
Doc Brown du
1
@Dari Parce qu'il ajoute un surcoût totalement inutile à votre application
Lamak
1
@RobbieDee Nous avons déjà compris que vous n'aimez pas les clés alternatives, mais cela ne signifie pas qu'elles sont inutiles. J'aime l'approche guid car elle simplifie beaucoup de problèmes.
T. Sar - Rétablir Monica
1
@RobbieDee Nous n'utilisons pas SQL Server. Nous utilisons MySql. Et cela se produit parce que quelqu'un va créer quelque chose sur Prod, disons avec l'ID 1234. Sur Dev, naturellement, nous créons beaucoup plus d'entités que sur Prod. 1234 a été prise il y a longtemps par une entité jetable pour être testée. Lorsque nous devons tester une entité à partir de prod, nous devons la migrer vers Dev - et sa clé primaire est déjà utilisée. La migration est beaucoup plus facile si les références à cette entité sont basées sur GUID. Mais la mise en veille prolongée fonctionne beaucoup mieux avec une clé primaire étant int ou longue, donc nous gardons cela. Mes développeurs ne sont pas paresseux ou ignorants - ils sont aguerris.
corsiKa
9

La plupart des factures ont un numéro de facture qui, selon la plupart des règles comptables, doit être séquentiel ou un comptable peut ne pas approuver les résultats de l'année ou l'IRS (ou similaire dans votre pays) peut souhaiter effectuer un audit complet sur vos onglets.

Un utilisateur peut déduire du numéro de facture le nombre de clients que vous avez servis ou la durée avant de modifier la stratégie de numérotation des factures.

Le nombre de factures stockées dans la base de données n'est pas une mesure du grand total de vos factures. Il existe d'autres moyens de le savoir, notamment en demandant vos rapports annuels à la Chambre de commerce.

Je voudrais cependant verrouiller la facture derrière un écran de connexion utilisateur, afin que tout le monde ne puisse pas la demander. Ensuite, lors de la connexion de l'utilisateur, il peut utiliser une méthodologie ajax pour demander ses factures en suspens, etc. et vous contrôlez la façon dont les données sont affichées et proposées.

Tschallacka
la source
7
Une stratégie courante utilisée dans le secteur bancaire (avec des numéros de chèque) consiste à ne pas commencer le décompte incrémentiel à 1, mais plutôt un nombre plus élevé pour cette raison exacte.
DanK
Je pense que c'est pourquoi l'id doit être une clé primaire supplémentaire, pas un remplacement de l'ancienne clé primaire.
Alexander
1
Je n'appellerais pas cela une clé primaire. J'irais pour un slug, un UUID comme nom, mais en substance c'est juste un autre champ indexé dans la table. Identifiant, numéro de facture, etc. C'est un champ, mais pas une clé primaire. Une clé primaire doit être unique et peut être utilisée en interne pour la cartographie relationnelle. Si le champ est indexé, il peut être recherché rapidement par une requête where. userXveryY.where ('numéro_de_facture', 'foobarbaz10'). get ();
Tschallacka
1
Vous répondez à une question technique en arguant qu'elle n'est pas nécessaire en raison des particularités américaines (numéros de facture séquentiels requis, rapports à la Chambre de commerce). OMI, cela ne répond pas bien à la question.
RemcoGerlich
7

Vous pouvez peut-être utiliser des hachages pour cela, il est conçu pour résoudre exactement ce scénario.

Il encodera votre ID de base de données en un hachage court (similaire à l'URL d'une vidéo YouTube), et il ne vous demandera pas d'ajouter de clés secondaires à votre table.

mitchdav
la source
2
Le nom est quelque peu trompeur, car il ne s'agit pas d'un hachage, mais d'une fonction réversible. Mais cela semble être la solution parfaite au problème.
Crazy Yoghurt
2
@CrazyYoghurt True ... ils ont abordé la raison du nom comme ils l'ont fait ici: hashids.org/#why-hashids
Eric King
3

Vous pouvez créer une autre clé unique, mais vous ne devriez pas. Pas pour la raison donnée. Il existe des moyens plus simples de masquer les tailles de table.

Le stockage N_8Zk241vNacoûte 12 octets par ligne dans le tableau et encore plus dans l'index. C'est assez inutile pour ce dont vous avez besoin.

Le chiffrement de l'entier idne vous coûte aucun espace et presque rien pendant l'exécution. La façon dont vous le faites dépend de votre langage de programmation et / ou de votre base de données.

Notez qu'avec AES, vous obtenez un entier de 128 bits, ce qui signifie 22 caractères en base64, probablement plus que vous ne le souhaitez. Un chiffre avec une taille de bloc de 64 comme DES ou 3DES vous donne 11 caractères, comme vous le souhaitez.

Utilisez différentes clés pour différentes tables.

Si tout ce dont vous avez besoin est de masquer les tailles des tables, vous pouvez utiliser une séquence commune pour toutes les tables. Notez qu'il peut s'agir d'un goulot d'étranglement s'il y a des insertions fréquentes dans plusieurs de vos tables. Avec quelque chose comme Hibernate et un algorithme Hi-Lo, ce problème disparaît.

maaartinus
la source
Exactement - stocker cette valeur juste pour en cacher une autre est tout simplement faux.
Robbie Dee
Cela peut fonctionner dans ce scénario car un ID de facture n'est pas vraiment confidentiel, mais en règle générale, l'utilisation d'ID confidentiels comme structure relationnelle dans une base de données provoquera un mal de tête royal si vous devez masquer des données à un moment donné dans le futur. Mieux vaut les traiter comme un attribut.
DanK
comment puis-je appliquer aes ici?
Dari
@Dari Comment pouvez-vous appliquer AES à quoi que ce soit ? Sans connaître votre langue, personne ne peut le dire. Habituellement, AES fonctionne avec un byte[], vous pouvez écrire votre iden quatre ou huit octets, ajouter un numéro de table unique et crypter (l'entrée doit être exactement 16 octets). S'il y a des modes à choisir, la BCE a raison.
maaartinus
@DanK Quoi? Affirmez-vous que AES n'est pas sûr? Sans connaître la clé, l'attaquant ne pourrait rien faire de mieux que pour un attribut stocké. Rien. +++ Je suppose que je ne comprends pas votre commentaire.
maaartinus
0

À mon humble avis, la création de deux clés primaires différentes n'est pas possible. Bien sûr, vous pouvez mettre cet uuid dans une base de données pour l'avoir comme "alias" pour la clé primaire actuelle. Vous pouvez placer un index au-dessus de cette colonne avec une contrainte unique, mais la clé primaire est (par essence) unique dans une seule table. Il peut y avoir une clé primaire composite, mais ce n'est pas ce que vous recherchez.

Je suggère donc de le mettre là, mais de ne l'avoir qu'avec index. Vous pouvez créer un composant de gestion pour interroger les données par PK ainsi que d'autres colonnes uniques. Lors du traitement de la demande de "/ factures / ...", vérifiez simplement le paramètre - s'il est entier, recherchez l'ID, sinon recherchez uuid. Ou vous pouvez avoir la recherche uuid comme solution de rechange lorsque la recherche d'ID n'a rien trouvé.

Et à propos de la génération d'uuids "aléatoires": Pourquoi pas quelque chose comme "prendre l'ID, ajouter CONSTANT, convertir en hexadécimal". L'unicité de l'ID fournira l'unicité de l'uuid, le nombre hexadécimal est plus difficile à lire pour les mortels normaux + l'ajout d'une constante évitera d'avoir l'uuid comme 00000001.

Jarda
la source
1
"Pourquoi pas quelque chose comme" prendre ID, ajouter CONSTANT, convertir en hexadécimal "- parce que c'est assez facile à comprendre - donnez-moi une URL et je vais jeter un œil à toutes les autres factures dans le système. IMO il n'y a pas de problème que cela résout réellement, juste ceux qu'il crée potentiellement.
CompuChip
" Lors de la gestion de la demande de" / factures / ... ", vérifiez simplement le paramètre - s'il est entier, recherchez l'ID , sinon recherchez uuid " Le but (si je comprends bien la question) est d'empêcher quelqu'un de rechercher par ID ( /invoices/123, /invoices/124, ...) afin que vous ne recherchiez que par UUID depuis l'URL.
TripeHound
De plus, tous les nombres hexadécimaux ne contiennent pas de lettres. Il serait impossible de toujours distinguer entre vos entiers sous-jacents et vos nombres hexadécimaux générés.
TRiG
@CompuChip comme je l'attends, vous êtes intéressé par les ordinateurs :-) donc vous reconnaissez le numéro hexadécimal pour la première vue. Mais le Q a été écrit de manière à ne pas montrer directement le numéro de facture pour permettre aux autres de savoir combien il y a de factures. Quand je montre un nombre hexadécimal à ma femme, ma mère, mon voisin ... ils ne sauront pas ce qu'est ce "texte étrange". S'il y aura un avis sur un problème de sécurité en fonction des numéros de facture dans le Q, je suggérerais une méthode de hachage complexe à cet effet.
Jarda
@TripeHound, il pourrait toujours être en mesure de rechercher par ID en interne ou dans un point d'entrée à accès limité ...
Jarda
0

Si les deux touches pointent vers le même fait, elles ne se heurteraient jamais. Pourquoi ne pas dériver l'autre clé de celle d'origine en utilisant une fonction scalaire qui créerait un code de hachage personnalisé de votre clé d'origine.

vous pouvez également créer une table de mappage annexe, qui stockerait les deux versions de la clé. cette table servira de dictionnaire pour rechercher la clé secondaire.

Selon ma compréhension, les clés sont des indices implicites et plus vous ajoutez d'indices, plus les insertions seront lentes.

A.Rashad
la source
+1 Oui, l'ajout de ce qui est potentiellement une grande colonne de chaînes avec un index n'est certainement pas l'opération sans valeur que d'autres suggèrent. Les frais généraux de stockage mis à part, à mesure que les index sont ajoutés, la vitesse d'insertion commence à se dégrader.
Robbie Dee
0

Une autre approche pour votre cas d'utilisation particulier est qu'au lieu de modifier la base de données et l'application, vous pouvez simplement créer un itinéraire personnalisé vers les factures de sorte que le / factures /: f (id) où f (id) est une fonction de l'id.

L'itinéraire personnalisé est chargé de mapper une demande à l'action correcte côté serveur.


la source
0

C'est une pratique totalement acceptable, également appelée «clé alternative» (AK). Fondamentalement, l'AK est un autre index unique ou une contrainte unique.

Vous pouvez même créer des contraintes de clé étrangère en fonction de votre AK.

Un cas d'utilisation possible est comme ce que vous avez expliqué: vous avez un PK en cluster sur un numéro d'identité en constante augmentation, mais vous ne voulez pas que ce numéro soit affiché ou utilisé comme critère de recherche, car il peut simplement être deviné. Donc, en plus, vous avez un identifiant unique aléatoire ou un numéro de référence comme AK, et c'est l'ID que vous présentez à l'utilisateur

Alex Schievink
la source
0

Il existe plusieurs types de clés / index. Une clé primaire est un index unique spécial et, comme le disent les réponses, vous pouvez certainement créer une autre clé unique. Et je conviens qu'il est préférable de ne pas exposer les éléments internes de votre base de données à moins qu'il n'y ait une très bonne raison.

Étant donné que la question se situe dans le contexte des factures et des numéros, il pourrait être utile de rechercher à quoi le secteur comptable s'attend à ce que les numéros de facture ressemblent: http://smallbusiness.chron.com/assign-invoice-numbers-52422.html

Il peut sembler compliqué d'avoir un identifiant interne qui est une clé primaire et un autre champ unique avec le numéro de facture visible de l'application / du client. Mais ce n'est pas si sale quand, disons un an plus tard, le client veut adopter un nouveau schéma de numérotation des factures. Dans ce cas, vous ne dérangeriez pas l'identifiant interne et ses relations dans d'autres tableaux pour renuméroter la boule de cire entière. Vous devez conserver votre ID interne tel quel et renuméroter le numéro de facture non interne.

Idéalement, vous vous efforcez de ne pas lier les tables ensemble sur des clés / clés étrangères susceptibles de changer, et de garder vos tables et relations internes transparentes pour la couche d'application.

Thomas Carlisle
la source
0

Fonce.

Ce n'est pas différent d'un champ "slug" que les articles de blog et similaires ont souvent - une façon unique de se référer à l'enregistrement de base de données distinct de la clé primaire, apte à être utilisé dans une URL. Je n'ai jamais entendu personne argumenter contre cela.

RemcoGerlich
la source