les clés primaires composites sont une mauvaise pratique? [fermé]

14

Je veux savoir si les clés primaires composites sont une mauvaise pratique et sinon, sur quels scénarios il est recommandé d'utiliser.

Ma question est basée sur cet article

erreurs de conception des bases de données

La partie sur les clés primaires composites:

Mauvaise pratique n ° 6: clés primaires composites

C'est une sorte de point controversé, car de nombreux concepteurs de bases de données parlent aujourd'hui d'utiliser un champ généré automatiquement par un identifiant entier comme clé primaire au lieu d'un champ composite défini par la combinaison de deux champs ou plus. Ceci est actuellement défini comme la «meilleure pratique» et, personnellement, j'ai tendance à être d'accord avec elle.

Image d'une clé primaire composite

Cependant, ce n'est qu'une convention et, bien sûr, les DBE permettent la définition de clés primaires composites, ce que de nombreux concepteurs pensent inévitable. Par conséquent, comme pour la redondance, les clés primaires composites sont une décision de conception.

Attention, cependant, si votre table avec une clé primaire composite devrait contenir des millions de lignes, l'index contrôlant la clé composite peut atteindre un point où les performances de l'opération CRUD sont très dégradées. Dans ce cas, il est préférable d'utiliser une clé primaire d'ID entier simple dont l'index sera suffisamment compact et d'établir les contraintes DBE nécessaires pour maintenir l'unicité.

hackvan
la source
4
Ce n'est pas une "bonne" ou "mauvaise" pratique. Chaque décision de conception doit servir un objectif; si vous pouvez expliquer (à vous-même et aux autres) pourquoi vous avez besoin d'un PK composite, vous êtes prêt à partir. À l'inverse, si vous pouvez expliquer pourquoi vous n'en avez pas besoin, vous pouvez également y aller. L'article auquel vous liez fait un très mauvais travail d'explication, à mon avis.
mustaccio
cet article signale un point, mais si nous regardons les frameworks populaires (comme les rails par exemple) dans ses "meilleures pratiques" ne supporte pas ce type de clés primaires, alors j'ai demandé pourquoi? c'est pour des difficultés techniques ou autre chose.
hackvan
Il est plus facile pour les conceptions de framework de simplement prendre en charge les clés primaires entières à simple colonne "simples". Et comme la plupart des développeurs (du moins d'après mon expérience personnelle) n'ont pas beaucoup de compétences en base de données (par rapport aux utilisateurs de ce site, au moins), cela fonctionne assez bien pour la plupart des utilisateurs du logiciel. Étant donné que la plupart des utilisateurs du logiciel n'ont pas besoin de clés composites (ou ne pensent pas qu'ils en ont besoin, au moins au début), ils peuvent donc se passer de ne pas fournir un (bon) support pour les clés composites.
Willem Renzema
1
Comment un GUID est-il meilleur qu'un INTEGER [Série | Auto_Increment | Identité | <whthing_integer_you_like>]?
Vérace
4
Je n'embaucherais pas cet auteur
paparazzo

Réponses:

31

Dire que l'utilisation de "Composite keys as PRIMARY KEY is bad practice"est totalement absurde!

Les composites PRIMARY KEYsont souvent une très bonne chose et la seule façon de modéliser des situations naturelles qui se produisent dans la vie de tous les jours!

Pensez à l'exemple classique d'enseignement des bases de données des étudiants et des cours et aux nombreux cours suivis par de nombreux étudiants!

Créer un cours de tables et étudiant:

CREATE TABLE course
(
  course_id SERIAL,
  course_year SMALLINT NOT NULL,
  course_name VARCHAR (100) NOT NULL,
  CONSTRAINT course_pk PRIMARY KEY (course_id)
);


CREATE TABLE student
(
  student_id SERIAL,
  student_name VARCHAR (50),
  CONSTRAINT student_pk PRIMARY KEY (student_id)
);

Je vais vous donner l'exemple dans le dialecte PostgreSQL (et MySQL ) - devrait fonctionner pour n'importe quel serveur avec un peu de peaufinage.

Maintenant, vous voulez évidemment savoir quel étudiant suit quel cours - vous avez donc ce qu'on appelle un joining table(aussi appelé linking, many-to-manyou m-to-ntables). Ils sont aussi connus comme associative entitiesdans un jargon plus technique!

1 cours peut avoir de nombreux étudiants.
1 étudiant peut suivre de nombreux cours.

Donc, vous créez une table de jonction

CREATE TABLE course_student
(
  cs_course_id INTEGER NOT NULL,
  cs_student_id INTEGER NOT NULL,

  -- now for FK constraints - have to ensure that the student
  -- actually exists, ditto for the course.

  CREATE CONSTRAINT cs_course_fk FOREIGN KEY (cs_course_id) REFERENCES course (course_id),
  CREATE CONSTRAINT cs_student_fk FOREIGN KEY (cs_student_id) REFERENCES student (student_id)
);

Maintenant, la seule façon de donner un sens à cette table PRIMARY KEYest d'en faire KEYune combinaison de cours et d'étudiant. De cette façon, vous ne pouvez pas obtenir:

  • un double de la combinaison étudiant / cours

    • un cours ne peut avoir le même étudiant inscrit qu'une seule fois, et

    • un étudiant ne peut s'inscrire au même cours qu'une seule fois

  • vous avez également une recherche prête à l'emploi KEYsur le cours par étudiant - AKA un index de couverture ,

  • il est trivial de trouver des cours sans étudiants et sans étudiants!

    - L' exemple db-fiddle a la contrainte PK repliée dans la CREATE TABLE - Cela peut être fait dans les deux sens. Je préfère avoir tout dans l'instruction CREATE TABLE.


ALTER TABLE course_student 
ADD CONSTRAINT course_student_pk 
PRIMARY KEY (cs_course_id, cs_student_id);

Maintenant, vous pourriez, si vous trouviez que les recherches d'étudiants par cours étaient lentes, utiliser un UNIQUE INDEXon (sc_student_id, sc_course_id).

ALTER TABLE course_student 
ADD CONSTRAINT course_student_sc_uq  
UNIQUE (cs_student_id, cs_course_id);

Il n'y a pas de solution miracle pour l' ajout d' index - ils vont faire INSERTl et UPDATEest plus lent, mais au grand avantage de énormement décroissanteSELECT fois! C'est au développeur de décider d'indexer en fonction de ses connaissances et de son expérience, mais dire que les composites PRIMARY KEYsont toujours mauvais est tout simplement faux.

Dans le cas de joindre des tables, ce sont généralement les seules PRIMARY KEY qui ont du sens! Rejoindre des tables est aussi très souvent le seul moyen de modéliser ce qui se passe en entreprise ou dans la nature ou dans pratiquement tous les domaines auxquels je peux penser!

Ce PK est également utilisé comme un covering indexqui peut aider à accélérer les recherches. Dans ce cas, il serait particulièrement utile de rechercher régulièrement (course_id, student_id) ce qui, on pourrait l'imaginer, peut souvent être le cas!

Ceci est juste un petit exemple où un composite PRIMARY KEYpeut être une très bonne idée, et la seule façon sensée de modéliser la réalité! Du haut de ma tête, je peux penser à beaucoup d' autres.

Un exemple de mon propre travail!

Considérez une table de vol contenant un flight_id, une liste des aéroports de départ et d'arrivée et les heures pertinentes, puis aussi une table de cabine avec des membres d'équipage!

La seule façon raisonnable de modéliser cela est d'avoir une table flight_crew avec les attributs flight_id et crew_id et la seule raison PRIMARY KEYest d'utiliser la clé composite des deux champs!

Vérace
la source
2
dans l'exemple de cours et d'étudiants, est-il possible que course_student ait une idclé primaire et un index unique sur cs_student_id cs_course_idet ait les mêmes résultats?
hackvan
2
Pourquoi gaspiller des ressources en faisant cela? Avec PK (course_id, student_id), par définition, vous avez déjà un index unique sur ces champs! Un index unique sur (student_id, course_id) pourrait être utile pour accélérer les recherches - par exemple, si vous recherchez des étudiants qui ne suivaient aucun cours, mais cette décision pourrait être opérationnelle, mais en ces jours de stockage relativement bon marché, Je le recommanderais, d'autant plus que l'on pourrait penser que le tableau ne sera pas mis à jour très fréquemment.
Vérace
1
D'accord pour les tables de liens - je travaille avec plusieurs en ce moment. Cependant, lorsque je mets mon chapeau C #, je travaille avec le générateur reversepoco et je crée des classes utiles (trouver, enregistrer, etc.) pour la couche suivante. J'ai rencontré un problème majeur - les clés composites deviennent un PITA pour avoir n'importe quel code générique de sauvegarde / recherche. Oui, je pourrais peut-être revenir aux fichiers EDMX mais je dois encore contourner le code de cas spécial (compter les colonnes Pkey?) Ou ajouter une clé de substitution artificielle (je n'aime pas et j'ai besoin de contraintes d'unicité supplémentaires :(). Donc, je suppose les gens qui n'aiment pas les composites parlent du code de la couche App
Richard Griffiths
En fonction de la fréquence des inserts et de la fréquence de défragménation de l'indice vs fenêtre de maintenance, c'est la meilleure solution. Mais certains choix de conception sont des compromis motivés par des exigences qui peuvent ne pas être immédiatement visibles. Mais comme l'a dit un commentaire, identifiez les avantages / inconvénients des deux scénarios et faites un choix de conception.
Jonathan Fite
Que se passe-t-il lorsqu'un étudiant répète le cours? Ensuite, à moins que les cours séparés dans le temps n'obtiennent des identifiants différents - alors vous avez encore une autre table de mappage. Ou ajoutez un champ pour la date du cours qui doit maintenant être ajouté à la clé.
iheanyi
3

Ma vision à moitié instruite: une "clé primaire" ne doit pas être la seule clé unique utilisée pour rechercher des données dans la table, bien que les outils de gestion des données la proposent comme sélection par défaut. Ainsi, pour choisir si vous souhaitez avoir un composite de deux colonnes ou un nombre généré (probablement en série) comme clé de table, vous pouvez avoir deux clés différentes à la fois.

Si les valeurs de données incluent un terme unique approprié qui peut représenter la ligne, je préfère déclarer cela comme "clé primaire", même si composite, plutôt que d'utiliser une clé "synthétique". La clé synthétique peut mieux fonctionner pour des raisons techniques, mais mon propre choix par défaut est de désigner et d'utiliser le terme réel comme clé primaire, à moins que vous n'ayez vraiment besoin d'aller dans l'autre sens pour faire fonctionner votre service.

Un serveur Microsoft SQL a la caractéristique distincte mais liée de l '"index clusterisé" qui contrôle le stockage physique des données dans l'ordre des index, et est également utilisé à l'intérieur d'autres index. Par défaut, une clé primaire est créée en tant qu'index cluster, mais vous pouvez choisir à la place non cluster, de préférence après avoir créé l'index cluster. Ainsi, vous pouvez avoir une colonne générée par une identité entière comme index cluster et, par exemple, le nom de fichier nvarchar (128 caractères) comme clé primaire. Cela peut être mieux car la clé d'index cluster est étroite, même si vous stockez le nom de fichier comme terme de clé étrangère dans d'autres tables - bien que cet exemple soit un bon cas pour ne pas le faire également.

Si votre conception implique d'importer des tables de données qui incluent une clé primaire gênante pour identifier les données liées, vous êtes à peu près coincé avec cela.

https://www.techopedia.com/definition/5547/primary-key décrit un exemple de choix entre stocker des données avec le numéro de sécurité sociale d'un client comme clé client dans toutes les tables de données ou générer un identifiant client arbitraire lorsque vous les enregistrer. En fait, il s'agit d'un grave abus du SSN, qu'il fonctionne ou non; il s'agit d'une valeur de données personnelles et confidentielles.

Ainsi, l'avantage d'utiliser un fait réel comme clé est que, sans rejoindre la table "Client", vous pouvez récupérer des informations à leur sujet dans d'autres tables - mais c'est aussi un problème de sécurité des données.

De plus, vous avez des problèmes si le SSN ou une autre clé de données a été enregistré de manière incorrecte, vous avez donc la mauvaise valeur dans 20 tableaux contraints au lieu de "Client" uniquement. Alors que le customer_id synthétique n'a aucune signification externe, il ne peut donc pas être une mauvaise valeur.

Robert Carnegie
la source
1
J'apprécie particulièrement l'observation selon laquelle, en fonction des données client comme clé, même des données client uniques connues (ici, SSN), tombe en panne si ces données doivent être corrigées.
ToolmakerSteve