Question

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

Aurions-nous intérêt à 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 la clé métier?

Veuillez fournir des exemples ou des preuves à l'appui de votre théorie.

Était-ce utile?

La solution

Les deux. Prenez votre gâteau et mangez-le.

N'oubliez pas qu'une clé primaire n'a rien de spécial, sauf qu'elle est étiquetée en tant que 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 qui garantisse l'unicité des règles métier.

Autres conseils

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

  1. Stabilité : la modification d'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 de définir une convention d'appellation des colonnes de clé primaire normalisée plutôt que de devoir réfléchir à la manière 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 clé PK, une clé de substitution d'un entier peut être plus petite, plus rapide à indexer et à rechercher.

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

Un inconvénient des clés de substitution est qu’elles ne sont dénuées de sens (citées comme un 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 ne 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 " Quelqu'un dira "Que se passe-t-il lorsque le code de MYPROJECT, VALID ou HR change?" Ce à quoi ma réponse serait: "Pourquoi auriez-vous besoin de le changer?" Ce ne sont pas " naturel " clés dans le sens où un organisme extérieur va légiférer pour que «VALIDE» soit dorénavant «recodé» comme étant «BON». Seul un petit pourcentage de " naturel " les clés entrent vraiment dans cette catégorie - SSN et Zip Code étant les exemples habituels. J'utiliserais certainement une touche numérique dénuée de sens pour des tables telles que Person, Address - mais pas pour tout , que la plupart des gens ici semblent préconiser pour une raison quelconque.

Voir aussi: ma réponse à une autre question

Les clés de substitution (généralement des entiers) ont pour valeur ajoutée de rendre vos relations de table plus rapides, et 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 lorsque vous utilisez des clés de substitution, contrairement à l'entreprise champs clés, qui changent 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. Pensez à la table Personnes: 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 de Merkia. Vous êtes assez malin pour ne pas utiliser le nom de la société comme clé primaire. Vous utilisez donc l'identifiant de société unique du gouvernement de Merkia, composé 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 ont 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 facilite les jointures, le premier évite un autre index (ou peut-être plusieurs, si vous souhaitez également regrouper vos commandes 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é d'entreprise.

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

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é. Il est plutôt absurde, quand on y pense, de penser que l'ajout de données dénuées de sens à 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’identité de substitution.

  3. Lorsque des clés de substitution sont utilisées comme clés primaires, leur définition est bien moins claire. 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 entraîne le remplissage des 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 suggère que vous deviez stocker un entier de substitution au lieu de la valeur elle-même.

  6. J'ai trois bases de données différentes. Aucun d’entre eux ne montre à l’aide de clés de substitution.

Je souhaite partager mon expérience avec vous sur cette guerre sans fin: D sur un dilemme clé 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 des avantages et des 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 des problèmes de performances:
    • Elles sont généralement implémentées à l'aide de colonnes auto-incrémentées, ce qui signifie:
      • 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 similaires, 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 mon entreprise, au moins), vous risquez 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 certainement avec des conflits sur votre base de données.
  2. sujet aux erreurs. Une séquence a une limite max_value. Par conséquent, 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 être le cas, 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 la non duplication des donné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, c’est le THE problème des clés de substitution du point de vue de la conception de la base de données.
  4. Plus sur 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, numéro de vol opérationnel). Plus généralement, lorsqu'un standard donné garantit à un ensemble de données de l'entreprise d'être unique, il constitue un [bon] candidat clé naturel.
  3. Les clés naturelles " polluent le schéma " des tables d'enfant. Pour moi, c'est plus un sentiment qu'un vrai problème. Avoir une clé primaire à 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 des clés naturelles lorsqu'il est pertinent de le faire et des clés de substitution lorsqu'il est préférable de les utiliser.

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

Utilisez toujours une clé qui n’a pas de sens commercial. C'est juste une bonne pratique.

EDIT: J'essayais de trouver un lien vers ce site en ligne, mais je ne pouvais pas. Toutefois, dans 'Modèles d'architecture d'entreprise' [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 d'être une clé. Cela se résume au fait qu’il devrait avoir un seul travail et un seul travail.

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 sûr, les puristes de la base de données diront que même la notion de clé de substitution est une abomination.)

Je suis fan des uids pour les clés de substitution, le cas échéant. La principale victoire avec eux est que vous connaissez la clé à l’avance, par exemple. vous pouvez créer une instance d'une classe avec l'ID déjà défini et garanti d'être unique, alors 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 et de déterminer si elles sont souhaitables.

À mon avis, l’utilisation d’une clé de substitution est préférable, car elle n’a aucune chance de changer. Presque tout ce que je pourrais imaginer et qui pourrait être utilisé 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 changés, donc ce serait une mauvaise idée. Vous ne voudriez vraiment pas le savoir après la publication de l'application, lorsque quelqu'un viendra à vous et voudra savoir pourquoi il ne peut pas changer sa plaque d'immatriculation en une nouvelle et personnalisée brillante.

Utilisez toujours une seule colonne, si possible une clé de substitution. 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 conserver l'enregistrement.

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

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

Sur un scénario d'entrepôt de données, 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.

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’existe aucun 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-ci, 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.

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 physiquement ces données. Vous devez plutôt placer des index uniques sur ces données, bien qu'il soit également avantageux de simplement exécuter 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 le fil @ http : //social.msdn.microsoft.com/Forums/en-us/sqlgetstarted/thread/27bd9c77-ec31-44f1-ab7f-bd2cb13129be

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

.

Utilisez des clés professionnelles / 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 une table contenant des milliers d'insertions

.

Utilisez des clés de substitution / d'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 de jointure avec la table JOB, mais uniquement avec: "SELECT * FROM PEOPLE WHERE JOBCODE = 'PRG'"

Dans le deuxième 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 la recherche de la prochaine clé unique car la base de données elle-même vous donne le prochain auto-incrémentation.

C’est l’un des cas de figure où une clé de substitution toujours a un sens. Il existe des cas dans lesquels vous pouvez choisir ce qui convient le mieux à la base de données ou à votre modèle d'objet, mais dans les deux cas, l'utilisation d'une clé ou d'un GUID sans signification est une meilleure idée. Cela rend l’indexation plus facile et plus rapide, c’est une identité pour votre objet qui ne change pas.

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 qui fonctionne.

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 n'ont jamais fait surface. 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 joint interne Y sur Xa = Y.b", 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. pour 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.

Peut-être pas tout à fait pertinent pour ce sujet, mais un mal de tête que j'ai avec les clés de substitution. Les analyses prédéfinies Oracle créent des SK générées automatiquement sur toutes ses tables de dimensions de l'entrepôt, et les stockent é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 un rechargement complet 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 disques originaux / anciens. Comme beaucoup le savent, les solutions prêtes à l'emploi répondent rarement aux besoins d'une organisation et nous devons les personnaliser en permanence. 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, ils ne sont pas générés à partir de la saisie de données, mais ajoutés 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.

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top