web-dev-qa-db-fra.com

les clés primaires composites sont une mauvaise pratique?

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 cela article

databases design mistakes

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 of a composite primary key

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 doit 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é.

14
hackvan

Dire que l'utilisation de "Composite keys as PRIMARY KEY is bad practice" est un non-sens absolu!

Composite PRIMARY KEYs sont souvent une très bonne chose et la seule façon de modéliser des situations naturelles qui se produisent dans la vie quotidienne!

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 (également appelé linking, many-to-many ou m-to-n les tables). Ils sont également connus sous le nom de associative entities dans un jargon plus technique!

1 cours peut avoir de nombreux étudiants.
1 l'élève peut suivre plusieurs 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 manière de donner à cette table un PRIMARY KEY est de faire de KEY une 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 KEY sur le cours par étudiant - AKA a indice de couverture ,

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

    - Le db-fiddle exemple a la contrainte PK repliée dans 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 constatiez que les recherches d'étudiants par cours étaient lentes, utiliser un UNIQUE INDEX on (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 ajouter des index - ils feront faire INSERTs et UPDATEs plus lentement, mais au grand avantage de diminuer énormément SELECT fois! C'est au développeur de décider d'indexer en fonction de ses connaissances et de son expérience, mais de dire que le composite PRIMARY KEYs sont toujours mauvais est tout simplement faux.

Dans le cas de la jonction de tables, ce sont généralement les uniquement PRIMARY KEY c'est logique! 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 covering index qui 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 KEY peut ê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 beaucoup plus.

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 manière sensée que cela peut être modélisée consiste à avoir une table de flight_crew avec le flight_id et le crew_id en tant qu'attributs et le seul sensé PRIMARY KEY est d'utiliser la clé composite des deux champs!

31
Vérace

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 connexe 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, alors vous êtes à peu près coincé avec cela.

https://www.techopedia.com/definition/5547/primary-key décrit un exemple de choix de stockage 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 pour générer un client_id arbitraire lorsque vous les enregistrez. En fait, c'est un grave abus du SSN, indépendamment du fait 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.

3
Robert Carnegie