web-dev-qa-db-fra.com

Clés de substitution / clés naturelles / commerciales

Nous y revoilà, le vieil argument se pose encore ...

Faudrait-il mieux avoir une clé métier en tant que clé primaire ou préférerions-nous avoir un identifiant de substitution (c'est-à-dire une identité SQL Server) avec une contrainte unique sur le champ de clé métier?

Veuillez fournir des exemples ou des preuves pour étayer votre théorie.

163
Manrico Corazzi

Tous les deux. Avoir votre gâteau et le manger.

N'oubliez pas qu'une clé primaire n'a rien de spécial, sauf qu'elle est étiquetée comme telle. Ce n'est rien de plus qu'une contrainte NOT NULL UNIQUE, et une table peut en avoir plusieurs.

Si vous utilisez une clé de substitution, vous souhaitez toujours une clé métier pour garantir l'unicité des règles métier.

91
Ted

Quelques raisons d'utiliser des clés de substitution:

  1. Stabilité: Changer une clé en raison d'un besoin commercial ou naturel aura un impact négatif sur les tables associées. Les clés de substitution doivent rarement, sinon jamais, être modifiées car aucune signification n'est liée à la valeur.

  2. Convention: Vous permet d'avoir une convention d'appellation des colonnes de clé primaire normalisée plutôt que de devoir réfléchir à la façon de joindre des tables avec différents noms pour leurs clés de performance.

  3. Vitesse: En fonction de la valeur et du type de PK, une clé de substitution d'un entier peut être plus petite, plus rapide à indexer et à rechercher.

113
Jay Shepherd

Il semble que personne n’ait encore dit quoi que ce soit à l’appui des clés non substitutives (j’hésite à dire "naturelles"). Alors voilà ...

Un inconvénient des clés de substitution est qu’elles ne sont pas de sens (cité comme avantage par certains, mais ...). Cela vous oblige parfois à joindre beaucoup plus de tables à votre requête que nécessaire. Comparer:

select sum(t.hours)
from timesheets t
where t.dept_code = 'HR'
and t.status = 'VALID'
and t.project_code = 'MYPROJECT'
and t.task = 'BUILD';

contre:

select sum(t.hours)
from timesheets t
     join departents d on d.dept_id = t.dept_id
     join timesheet_statuses s on s.status_id = t.status_id
     join projects p on p.project_id = t.project_id
     join tasks k on k.task_id = t.task_id
where d.dept_code = 'HR'
and s.status = 'VALID'
and p.project_code = 'MYPROJECT'
and k.task_code = 'BUILD';

À moins que quelqu'un pense sérieusement que ce qui suit est une bonne idée ?:

select sum(t.hours)
from timesheets t
where t.dept_id = 34394
and t.status_id = 89    
and t.project_id = 1253
and t.task_id = 77;

"Mais", dira quelqu'un, "que se passera-t-il lorsque le code de MYPROJECT, VALID ou HR changera?" A quoi ma réponse serait: "pourquoi auriez-vous besoin de pour le changer?" Ce ne sont pas des clés "naturelles" dans le sens où un organisme extérieur va légiférer pour que "VALID" soit dorénavant codé "BON". Seul un faible pourcentage de clés "naturelles" entrent vraiment dans cette catégorie - SSN et Code postal étant les exemples habituels. J'utiliserais certainement une clé numérique sans signification pour des tables telles que Person, Address - mais pas pour tout , ce que, pour une raison quelconque, la plupart des gens ici semblent préconiser.

Voir aussi: ma réponse à une autre question

67
Tony Andrews

La clé de substitution n'aura JAMAIS de raison de changer. Je ne peux pas en dire autant des clés naturelles. Noms de famille, courriels, numéros ISBN - ils peuvent tous changer un jour.

29
Rimantas

Les clés de substitution (généralement des entiers) ont pour valeur ajoutée de rendre vos relations de table plus rapides, plus économiques en termes de stockage et de rapidité de mise à jour (encore mieux, les clés étrangères n'ont pas besoin d'être mises à jour lors de l'utilisation de clés de substitution, contrairement aux champs de clé métier, cela change de temps en temps).

La clé primaire d'une table doit être utilisée pour identifier de manière unique la ligne, principalement à des fins de jointure. Table Think a Persons: les noms peuvent changer et ils ne sont pas garantis uniques.

Pensez aux entreprises: vous êtes une entreprise Merkin heureuse qui fait des affaires avec d’autres entreprises à Merkia. Vous êtes assez intelligent pour ne pas utiliser le nom de la société comme clé primaire. Vous utilisez donc l'identifiant de société unique du gouvernement Merkia dans son intégralité de 10 caractères alphanumériques. Ensuite, Merkia modifie les identifiants de société car ils pensaient que ce serait une bonne idée. Ce n'est pas grave, vous utilisez la fonctionnalité de mises à jour en cascade de votre moteur de base de données, pour un changement qui ne devrait pas vous concerner en premier lieu. Plus tard, votre entreprise se développe et vous travaillez maintenant avec une entreprise à Freedonia. Les identifiants de société Freedonian peuvent comporter jusqu'à 16 caractères. Vous devez agrandir la clé primaire de l'ID de la société (ainsi que les champs de la clé étrangère dans les commandes, les problèmes, les transferts d'argent, etc.), en ajoutant un champ Pays dans la clé primaire (ainsi que dans les clés étrangères). Aie! Guerre civile en Freedonia, elle est divisée en trois pays. Le nom de pays de votre associé doit être changé pour le nouveau; mises à jour en cascade à la rescousse. BTW, quelle est votre clé primaire? (Pays, Identifiant de la société) ou (Identifiant de la société, Pays)? Ce dernier aide les jointures, le premier évite un autre index (ou peut-être plusieurs, si vous souhaitez également que vos commandes soient regroupées par pays).

Tous ces éléments ne constituent pas une preuve, mais une indication qu'une clé de substitution identifiant de manière unique une ligne pour toutes les utilisations, y compris les opérations de jointure, est préférable à une clé métier.

29
tzot

Je déteste les clés de substitution en général. Ils ne doivent être utilisés qu'en l'absence de clé naturelle de qualité. C'est assez absurde quand on y pense, de penser que l'ajout de données sans signification à votre table pourrait améliorer les choses.

Voici mes raisons:

  1. Lors de l'utilisation de clés naturelles, les tables sont regroupées de la manière dont elles sont le plus souvent recherchées, ce qui accélère les requêtes.

  2. Lorsque vous utilisez des clés de substitution, vous devez ajouter des index uniques sur les colonnes de clés logiques. Vous devez toujours empêcher les données en double logique. Par exemple, vous ne pouvez pas autoriser deux organisations portant le même nom dans votre table d’organisation, même si le pk est une colonne d’identificateur de substitution.

  3. Lorsque des clés de substitution sont utilisées comme clé primaire, il est beaucoup moins clair de savoir quelles sont les clés primaires naturelles. Lors du développement, vous voulez savoir quel jeu de colonnes rend la table unique.

  4. Dans une à plusieurs chaînes de relations, les chaînes de clés logiques. Ainsi, par exemple, les organisations ont de nombreux comptes et les comptes ont de nombreuses factures. La clé logique de l'organisation est donc OrgName. La clé logique des comptes est OrgName, AccountID. La clé logique de la facture est OrgName, AccountID, InvoiceNumber.

    Lorsque des clés de substitution sont utilisées, les chaînes de clés sont tronquées car une clé étrangère est attribuée au parent immédiat. Par exemple, la table Facture n'a pas de colonne OrgName. Il a seulement une colonne pour le AccountID. Si vous souhaitez rechercher des factures pour une organisation donnée, vous devez joindre les tables Organisation, Compte et Facture. Si vous utilisez des clés logiques, vous pouvez alors interroger directement la table d'organisation.

  5. Le stockage des valeurs de clé de substitution des tables de recherche a pour effet de remplir les tables avec des entiers sans signification. Pour afficher les données, vous devez créer des vues complexes qui se joignent à toutes les tables de recherche. Une table de correspondance est destinée à contenir un ensemble de valeurs acceptables pour une colonne. Il ne devrait pas être codifié en stockant une clé de substitution entière. Rien dans les règles de normalisation ne vous suggère de stocker un entier de substitution à la place de la valeur elle-même.

  6. J'ai trois livres de base de données différents. Aucun d'entre eux ne montre à l'aide de clés de substitution.

26
Ken

Je souhaite partager mon expérience avec vous sur cette guerre sans fin: D sur un dilemme naturel vs clé de substitution. Je pense que les deux clés de substitution (clés artificielles auto-générées) et les clés naturelles (composées de colonnes avec une signification de domaine) ont avantages et inconvénients . Donc, selon votre situation, il pourrait être plus pertinent de choisir l'une ou l'autre méthode.

Comme il semble que de nombreuses personnes présentent les clés de substitution comme la solution presque parfaite et les clés naturelles comme la peste, je me concentrerai sur les arguments de l'autre point de vue:

Inconvénients des clés de substitution

Les clés de substitution sont:

  1. Source de problèmes de performance:
    • Ils sont généralement implémentés en utilisant des colonnes auto-incrémentées qui signifient:
      • Un aller-retour à la base de données à chaque fois que vous souhaitez obtenir un nouvel identifiant (je sais que cela peut être amélioré en utilisant la mise en cache ou des algorithmes [seq] hilo identiques, mais ces méthodes présentent néanmoins leurs propres inconvénients).
      • Si un jour vous devez déplacer vos données d'un schéma à un autre (cela se produit assez régulièrement dans ma société au moins), vous risquez alors de rencontrer des problèmes de collision Id. Et oui, je sais que vous pouvez utiliser des UUID mais ces derniers nécessitent 32 chiffres hexadécimaux! (Si vous vous souciez de la taille de la base de données, cela peut être un problème).
      • Si vous utilisez une séquence pour toutes vos clés de substitution, vous vous retrouverez avec certitude dans votre base de données.
  2. Erreur sujette. Une séquence a une limite max_value donc - en tant que développeur - vous devez faire attention aux points suivants:
    • Vous devez faire défiler votre séquence (lorsque la valeur maximale est atteinte, elle retourne à 1,2, ...).
    • Si vous utilisez la séquence comme un ordre (dans le temps) de vos données, vous devez gérer le cas du cycle (la colonne avec Id 1 peut être plus récente que la ligne avec Id max-valeur - 1).
    • Assurez-vous que votre code (et même vos interfaces clientes, ce qui ne devrait pas se produire car il est supposé être un identifiant interne) prend en charge les entiers 32b/64b que vous avez utilisés pour stocker vos valeurs de séquence.
  3. Ils ne garantissent pas les données non dupliquées. Vous pouvez toujours avoir 2 lignes avec toutes les mêmes valeurs de colonne mais avec une valeur générée différente. Pour moi, il s’agit [~ # ~] du problème [~ # ~] des clés de substitution du point de vue de la conception de base de données.
  4. Plus dans Wikipedia ...

Mythes sur les clés naturelles

  1. Les clés composites sont moins inefficaces que les clés de substitution. Non! Cela dépend du moteur de base de données utilisé:
  2. Les clés naturelles n'existent pas dans la vie réelle. Désolé mais ils existent! Dans l’industrie aéronautique, par exemple, le tuple suivant sera toujours unique pour un vol programmé donné (compagnie aérienne, date de départ, numéro de vol, suffixe opérationnel). Plus généralement, lorsqu'un ensemble de données commerciales est garanti d'être unique par un standard donné , cet ensemble de données constitue alors un [bon] candidat à clé naturelle.
  3. Les clés naturelles "polluent le schéma" des tables enfants. Pour moi, c'est plus un sentiment qu'un vrai problème. Avoir une clé primaire de 4 colonnes de 2 octets chacune pourrait être plus efficace qu'une seule colonne de 11 octets. En outre, les 4 colonnes peuvent être utilisées pour interroger directement la table enfant (en utilisant les 4 colonnes d'une clause where) sans rejoindre la table parent.

Conclusion

Utilisez les clés naturelles lorsque cela est pertinent et utilisez les clés de substitution lorsqu'il est préférable de les utiliser.

J'espère que cela a aidé quelqu'un!

17
mwnsiri

Utilisez toujours une clé qui n’a aucune signification professionnelle. C'est juste une bonne pratique.

EDIT: J'essayais de trouver un lien en ligne, mais je ne pouvais pas. Cependant, dans 'Patterns of Enterprise Archtecture' [Fowler], vous avez une bonne explication de la raison pour laquelle vous ne devriez pas utiliser autre chose qu'une clé sans signification autre que celle d'être une clé. Cela se résume au fait qu’il ne devrait y avoir qu’un seul travail.

15
Iain Holder

Les clés de substitution sont très pratiques si vous envisagez d'utiliser un outil ORM pour gérer/générer vos classes de données. Bien que vous puissiez utiliser des clés composites avec certains des mappeurs les plus avancés (read: hibernate), cela ajoute une certaine complexité à votre code.

(Bien entendu, les puristes de la base de données diront que même la notion de clé de substitution est une abomination.)

Je suis fan de l'utilisation des uids pour les clés de substitution lorsque cela convient. La principale victoire avec eux est que vous connaissez la clé à l’avance, par exemple. vous pouvez créer une instance d'une classe dont l'ID est déjà défini et garanti d'être unique, tandis qu'avec une clé entière, par exemple, vous devez définir par défaut la valeur 0 ou -1 et mettre à jour une valeur appropriée lorsque vous enregistrez/mettez à jour.

Les UID comportent des pénalités en termes de recherche et de rapidité d'adhésion, de sorte que cela dépend de l'application en question pour déterminer si elles sont souhaitables.

9
Derek Lawless

À mon avis, il est préférable d’utiliser une clé de substitution car il n’ya aucune chance que cela change. Presque tout ce que je pourrais penser que vous pourriez utiliser comme clé naturelle pourrait changer (disclaimer: pas toujours vrai, mais généralement).

Un exemple pourrait être une BD de voitures - à première vue, vous pourriez penser que la plaque d'immatriculation pourrait être utilisée comme clé. Mais ceux-ci pourraient être modifiés pour que ce soit une mauvaise idée. Vous ne voudriez pas vraiment savoir cela après relâchant l'application, quand quelqu'un vient vous demander pourquoi il ne peut pas changer sa plaque d'immatriculation en une nouvelle et brillante carte personnalisée.

6
Mark Embling

Toujours utiliser une seule colonne, clé de substitution si possible. Cela rend les jointures ainsi que les insertions/mises à jour/suppressions beaucoup plus propres car vous êtes uniquement responsable du suivi d'une seule information pour maintenir l'enregistrement.

Ensuite, si nécessaire, empilez vos clés d’entreprise sous forme de contraintes ou d’index uniques. Cela vous préservera l'intégrité des données.

La logique métier/les clés naturelles peuvent changer, mais la clé physique d'une table ne doit JAMAIS changer.

5
user7658

Dans un scénario de datawarehouse, je pense qu’il est préférable de suivre le chemin de la clé de substitution. Deux raisons:

  • Vous êtes indépendant du système source et les modifications qui y sont apportées - telles qu'un changement de type de données - ne vous concernent pas.
  • Votre DW aura besoin de moins d'espace physique, car vous n'utiliserez que des types de données entiers pour vos clés de substitution. De plus, vos index fonctionneront mieux.
4
Santiago Cepas

C'est l'un de ces cas où une clé de substitution a à peu près toujours un sens . Dans certains cas, vous pouvez choisir ce qui convient le mieux à la base de données ou à votre modèle d’objet, mais dans les deux cas, utiliser une clé dénuée de sens ou GUID est une meilleure idée. Il facilite l’indexation et plus vite, et c’est une identité pour votre objet qui ne change pas.

2
Charles Graham

Pour rappel, il est déconseillé de placer des index clusterisés sur des clés de substitution aléatoires, par exemple des GUID lisant XY8D7-DFD8S, car SQL Server n’est pas en mesure de trier ces données physiquement. Vous devez plutôt placer des index uniques sur ces données, bien qu'il soit également avantageux d'exécuter simplement le profileur SQL pour les opérations de la table principale, puis de placer ces données dans l'assistant de paramétrage du moteur de base de données.

Voir la discussion @ http://social.msdn.Microsoft.com/Forums/en-us/sqlgetstarted/thread/27bd9c77-ec31-44f1-ab7f-bd2cb13129be

2
Bryan Swan

Cas 1: Votre table est une table de consultation avec moins de 50 types (insertions)

Utilisez clés commerciales/naturelles. Par exemple:

Table: JOB with 50 inserts
CODE (primary key)       NAME               DESCRIPTION
PRG                      PROGRAMMER         A programmer is writing code
MNG                      MANAGER            A manager is doing whatever
CLN                      CLEANER            A cleaner cleans
...............
joined with
Table: PEOPLE with 100000 inserts

foreign key JOBCODE in table PEOPLE
looks at
primary key CODE in table JOB

Cas 2: Votre table est un table avec des milliers d'insertions

Utilisez clés de substitution/auto-incrémentation. Par exemple:

Table: ASSIGNMENT with 1000000 inserts
joined with
Table: PEOPLE with 100000 inserts

foreign key PEOPLEID in table ASSIGNMENT
looks at
primary key ID in table PEOPLE (autoincrement)

Dans le premier cas:

  • Vous pouvez sélectionner tous les programmeurs de la table PEOPLE sans utiliser la jointure avec la table JOB, mais simplement avec: "SELECT * FROM PEOPLE WHERE JOBCODE = 'PRG'"

Dans le second cas:

  • Vos requêtes de base de données sont plus rapides car votre clé primaire est un entier
  • Vous n'avez pas besoin de vous préoccuper de trouver la prochaine clé unique car la base de données elle-même vous donne le prochain auto-incrémentation.
2
Stefanos Kargas

Les clés de substitution peuvent être utiles lorsque les informations commerciales peuvent changer ou être identiques. Les noms commerciaux ne doivent pas nécessairement être uniques à travers le pays, après tout. Supposons que vous traitiez avec deux entreprises nommées Smith Electronics, une au Kansas et une au Michigan. Vous pouvez les distinguer par adresse, mais cela changera. Même l'état peut changer; Et si Smith Electronics de Kansas City (Kansas) traversait la rivière pour se rendre à Kansas City (Missouri)? Il n'y a pas de moyen évident de garder ces entreprises distinctes avec des informations de clé naturelle, une clé de substitution est donc très utile.

Pensez à la clé de substitution comme un numéro ISBN. Habituellement, vous identifiez un livre par son titre et son auteur. Cependant, j'ai deux livres intitulés "Pearl Harbor" par H. P. Willmott, et ce sont définitivement des livres différents, pas seulement des éditions différentes. Dans un cas comme celui-là, je pourrais faire référence à l'apparence des livres, ou au plus tôt au plus récent, mais c'est tout aussi bien que je dispose de l'ISBN.

2
David Thornley

Cheval pour les cours. Énoncer mon parti pris; Je suis un développeur avant tout, je suis donc principalement préoccupé de donner aux utilisateurs une application fonctionnelle.

J'ai travaillé sur des systèmes avec des clés naturelles et j'ai dû passer beaucoup de temps à faire en sorte que les changements de valeur se répercutent.

J'ai travaillé sur des systèmes avec uniquement des clés de substitution et le seul inconvénient est le manque de données dénormalisées pour le partitionnement.

La plupart des développeurs PL/SQL traditionnels avec lesquels j'ai travaillé n'aimaient pas les clés de substitution, à cause du nombre de tables par jointure, mais nos bases de données de test et de production ne faisaient jamais de bruit. les jointures supplémentaires n'ont pas affecté les performances de l'application. Avec les dialectes de base de données qui ne prennent pas en charge des clauses telles que "X jointure interne Y sur Xa = Yb", ou les développeurs qui n'utilisent pas cette syntaxe, les jointures supplémentaires pour les clés de substitution rendent les requêtes plus difficiles à lire et plus longues à taper et vérifier: voir @Tony Andrews post. Mais si vous utilisez un ORM ou tout autre framework de génération SQL, vous ne le remarquerez pas. La dactylographie atténue également.

1
WillC

Peut-être pas tout à fait pertinent pour ce sujet, mais un mal de tête que j'ai avec les clés de substitution. L'analyse prédéfinie Oracle crée des SK générés automatiquement sur toutes ses tables de dimensions de l'entrepôt, et les stocke également dans les faits. Ainsi, chaque fois que les dimensions doivent être rechargées au fur et à mesure que de nouvelles colonnes sont ajoutées ou doivent être renseignées pour tous les éléments de la dimension, les SK affectés lors de la mise à jour les synchronisent avec les valeurs d'origine stockées dans le fait, forçant une recharge complète de toutes les tables de faits qui s'y joignent. Je préférerais que même si le SK était un nombre sans signification, il y aurait un moyen de ne pas changer pour les enregistrements originaux/anciens. Comme beaucoup le savent, les solutions prêtes à l'emploi répondent rarement aux besoins d'une organisation et nous devons constamment les personnaliser. Nous avons maintenant une valeur de données de 3 ans dans notre entrepôt et les rechargements complets à partir des systèmes Oracle Financial sont très importants. Donc, dans mon cas, elles ne sont pas générées à partir de la saisie de données, mais ajoutées dans un entrepôt pour aider à la création de rapports de performances. Je comprends, mais les nôtres changent et c'est un cauchemar.

1
lrb

Dans le cas d'une base de données ponctuelle, il est préférable de combiner des clés de substitution et des clés naturelles. par exemple. vous devez suivre les informations d'un membre pour un club. Certains attributs d'un membre ne changent jamais. Par exemple, la date de naissance mais le nom peut changer. Créez donc une table Member avec une clé de substitution member_id et une colonne pour la date de naissance. Créez une autre table appelée nom de personne et définissez des colonnes pour member_id, member_fname, member_lname, date_updated. Dans cette table, la clé naturelle serait member_id + date_updated.

0
kanad