web-dev-qa-db-fra.com

Clés primaires composites et champ d'ID d'objet unique

J'ai hérité d'une base de données construite avec l'idée que les clés composites sont beaucoup plus idéales que l'utilisation d'un champ ID d'objet unique et que lors de la création d'une base de données, un seul ID unique devrait jamais être utilisé comme clé primaire. Parce que je construisais un front-end Rails pour cette base de données, j'ai rencontré des difficultés pour le faire se conformer aux conventions Rails) (même si c'était possible en utilisant custom vues et quelques gemmes supplémentaires pour gérer les clés composites).

Le raisonnement derrière cette conception de schéma spécifique de la personne qui l'a écrit était lié à la façon dont la base de données gère les champs d'identification de manière non efficace et quand elle crée des index, les tris d'arbres sont défectueux. Cette explication manquait de profondeur et j'essaie toujours de comprendre le concept (je suis familier avec l'utilisation de touches composites, mais pas à 100%).

Quelqu'un peut-il donner son avis ou approfondir ce sujet?

71
mwilliams

La plupart des moteurs couramment utilisés (MS SQL Server, Oracle, DB2, MySQL, etc.) ne rencontreraient pas de problèmes notables en utilisant un système de clé de substitution. Certains peuvent même bénéficier d'une amélioration des performances grâce à l'utilisation d'un substitut, mais les problèmes de performances sont très spécifiques à la plate-forme.

En termes généraux, le débat sur la clé naturelle (et par extension, la clé composite) vers la clé de substitution a une longue histoire sans probable "bonne réponse" en vue.

Les arguments des clés naturelles (singulières ou composites) incluent généralement les éléments suivants:

1) Ils sont déjà disponibles dans le modèle de données. La plupart des entités modélisées incluent déjà un ou plusieurs attributs ou combinaisons d'attributs qui répondent aux besoins d'une clé aux fins de créer des relations. L'ajout d'un attribut supplémentaire à chaque table intègre une redondance inutile.

2) Ils éliminent le besoin de certaines jointures. Par exemple, si vous avez des clients avec des codes client et des factures avec des numéros de facture (les deux sont " natural "), et que vous souhaitez récupérer tous les numéros de facture pour un code client spécifique, vous pouvez simplement utiliser "SELECT InvoiceNumber FROM Invoice WHERE CustomerCode = 'XYZ123'". Dans l'approche classique de la clé de substitution, le SQL ressemblerait à ceci: "SELECT Invoice.InvoiceNumber FROM Invoice INNER JOIN Customer ON Invoice.CustomerID = Customer.CustomerID WHERE Customer.CustomerCode = 'XYZ123'".

3) Ils contribuent à une approche plus universellement applicable de la modélisation des données. Avec les clés naturelles, la même conception peut être utilisée en grande partie inchangée entre les différents moteurs SQL. De nombreuses approches de clés de substitution utilisent des techniques de moteur SQL spécifiques pour la génération de clés, ce qui nécessite une plus grande spécialisation du modèle de données à implémenter sur différentes plates-formes.

Les arguments pour les clés de substitution ont tendance à tourner autour de problèmes spécifiques au moteur SQL:

1) Ils permettent de modifier plus facilement les attributs lorsque les exigences/règles métier changent. En effet, ils permettent d'isoler les attributs de données dans une seule table. Il s'agit principalement d'un problème pour les moteurs SQL qui n'implémentent pas efficacement les constructions SQL standard telles que les DOMAIN. Lorsqu'un attribut est défini par une instruction DOMAIN, les modifications de l'attribut peuvent être effectuées à l'échelle du schéma à l'aide d'une instruction ALTER DOMAIN. Différents moteurs SQL ont des caractéristiques de performances différentes pour modifier un domaine, et certains moteurs SQL n'implémentent pas du tout DOMAINS, de sorte que les modélisateurs de données compensent ces situations en ajoutant des clés de substitution pour améliorer la capacité à apporter des modifications aux attributs.

2) Ils permettent des implémentations plus faciles de la concurrence que les clés naturelles. Dans le cas de la clé naturelle, si deux utilisateurs travaillent simultanément avec le même ensemble d'informations, tel que une ligne client, et l'un des utilisateurs modifie la valeur de la clé naturelle, puis une mise à jour par le deuxième utilisateur échouera car le code client qu'ils mettent à jour n'existe plus dans la base de données. Dans le cas de la clé de substitution, la mise à jour sera traitée avec succès car des valeurs d'ID immuables sont utilisées pour identifier les lignes de la base de données, et non les codes client modifiables. Cependant, il n'est pas toujours souhaitable d'autoriser la deuxième mise à jour - si le code client a changé, il est possible que le deuxième utilisateur ne soit pas autorisé à procéder à sa modification car "l'identité" réelle de la ligne a changé - le deuxième utilisateur peut mettre à jour la mauvaise ligne. Ni les clés de substitution ni les clés naturelles, à elles seules, ne résolvent ce problème. Des solutions d'accès concurrentielles complètes doivent être traitées en dehors de la mise en œuvre de la clé.

3) Elles fonctionnent mieux que les clés naturelles. Les performances sont les plus directement affectées par le moteur SQL. Le même schéma de base de données implémenté sur le même matériel à l'aide de différents moteurs SQL aura souvent des caractéristiques de performances radicalement différentes, en raison des mécanismes de stockage et de récupération des données des moteurs SQL. Certains moteurs SQL se rapprochent étroitement des systèmes de fichiers plats, où les données sont en fait stockées de manière redondante lorsque le même attribut, tel qu'un code client, apparaît à plusieurs endroits dans le schéma de la base de données. Ce stockage redondant par le moteur SQL peut entraîner des problèmes de performances lorsque des modifications doivent être apportées aux données ou au schéma. D'autres moteurs SQL fournissent une meilleure séparation entre le modèle de données et le système de stockage/récupération, permettant des changements plus rapides des données et du schéma.

4) Les clés de substitution fonctionnent mieux avec certaines bibliothèques d'accès aux données et certains cadres d'interface graphique En raison de la nature homogène de la plupart des conceptions de clés de substitution (exemple: toutes les clés relationnelles sont entiers), les bibliothèques d'accès aux données, les ORM et les cadres d'interface graphique peuvent travailler avec les informations sans avoir besoin de connaissances particulières sur les données. Les clés naturelles, en raison de leur nature hétérogène (différents types de données, taille, etc.), ne fonctionnent pas aussi bien avec les boîtes à outils et bibliothèques automatisées ou semi-automatisées. Pour les scénarios spécialisés, tels que les bases de données Embedded SQL, la conception de la base de données avec une boîte à outils spécifique à l'esprit peut être acceptable. Dans d'autres scénarios, les bases de données sont des ressources d'informations d'entreprise, accessibles simultanément par plusieurs plates-formes, applications, systèmes de rapports et périphériques, et ne fonctionnent donc pas aussi bien lorsqu'elles sont conçues en mettant l'accent sur une bibliothèque ou un cadre particulier. De plus, les bases de données conçues pour fonctionner avec des boîtes à outils spécifiques deviennent un handicap lorsque la prochaine grande boîte à outils est introduite.

J'ai tendance à tomber du côté des touches naturelles (évidemment), mais je n'en suis pas fanatique. En raison de l'environnement dans lequel je travaille, où toute base de données que j'aide à concevoir peut être utilisée par une variété d'applications, j'utilise des clés naturelles pour la majorité de la modélisation des données et j'introduis rarement des substituts. Cependant, je ne fais pas tout mon possible pour essayer de réimplémenter des bases de données existantes qui utilisent des substituts. Les systèmes à clé de substitution fonctionnent très bien - pas besoin de changer quelque chose qui fonctionne déjà bien.

Il existe d'excellentes ressources pour discuter des mérites de chaque approche:

http://www.google.com/search?q=natural+key+surrogate+key

http://www.agiledata.org/essays/keys.html

http://www.informationweek.com/news/software/bi/201806814

88
JeremyDWill

Je développe des applications de base de données depuis 15 ans et je n'ai pas encore rencontré de cas où une clé non de substitution était un meilleur choix qu'une clé de substitution.

Je ne dis pas qu'un tel cas n'existe pas, je dis simplement que lorsque vous tenez compte des problèmes pratiques du développement d'une application qui accède à la base de données, généralement les avantages d'une clé de substitution commencent à submerger la pureté théorique de non -surroger les clés.

32
Darrel Miller

la clé primaire doit être constante et sans signification; les clés non de substitution échouent généralement à l'une ou aux deux exigences, éventuellement

  • si la clé n'est pas constante, vous avez un problème de mise à jour futur qui peut devenir assez compliqué

  • si la clé n'a pas de sens, alors elle est plus susceptible de changer, c'est-à-dire qu'elle n'est pas constante; voir au dessus

prenons un exemple simple et courant: un tableau des articles d'inventaire. Il peut être tentant de faire du numéro d'article (numéro de référence, code-barres, code de pièce ou autre) la clé primaire, mais un an plus tard tous les numéros d'article changent et il vous reste un très problème de mise à jour désordonnée de toute la base de données ...

EDIT: il y a une question supplémentaire qui est plus pratique que philosophique. Dans de nombreux cas, vous allez trouver une ligne particulière d'une manière ou d'une autre, puis la mettre à jour plus tard ou la retrouver (ou les deux). Avec les clés composites, il y a plus de données à suivre et plus de contraintes dans la clause WHERE pour la recherche ou la mise à jour (ou la suppression). Il est également possible que l'un des segments clés ait changé entre-temps !. Avec une clé de substitution, il n'y a toujours qu'une seule valeur à conserver (l'ID de substitution) et par définition elle ne peut pas changer, ce qui simplifie considérablement la situation.

22
Steven A. Lowe

Il sonne comme la personne qui a créé la base de données est du côté des clés naturelles du débat sur les clés naturelles et les clés de substitution.

Je n'ai jamais entendu parler de problèmes avec les btrees sur les champs d'identification, mais je ne l'ai pas non plus étudié en profondeur ...

Je tombe du côté de la clé de substitution: vous avez moins de répétition lorsque vous utilisez une clé de substitution, car vous ne répétez qu'une seule valeur dans les autres tables. Comme les humains rejoignent rarement les tables à la main, nous ne nous soucions pas de savoir si c'est un nombre ou non. De plus, comme il n'y a qu'une seule colonne de taille fixe à rechercher dans l'index, il est prudent de supposer que les substituts ont également un temps de recherche plus rapide par clé primaire.

11
Powerlord

L'utilisation des champs 'ID (objet) unique' simplifie les jointures, mais vous devriez viser à ce que l'autre clé (éventuellement composite) reste unique - ne relâchez PAS les contraintes non nulles et DOIT maintenir la contrainte d'unicité.

Si le SGBD ne peut pas gérer efficacement les entiers uniques, il a de gros problèmes. Cependant, l'utilisation à la fois d'un "ID (objet) unique" et de l'autre clé utilise plus d'espace (pour les index) que simplement l'autre clé et dispose de deux index à mettre à jour à chaque opération d'insertion. Ce n'est donc pas un cadeau - mais tant que vous conservez également la clé d'origine, tout ira bien. Si vous éliminez l'autre clé, vous rompez la conception de votre système; tout l'enfer finira par se déchaîner (et vous pourriez ou non apercevoir que l'enfer s'est déchaîné).

5
Jonathan Leffler

Je suis essentiellement membre de l'équipe clé de substitution, et même si j'apprécie et comprends des arguments tels que ceux présentés ici par JeremyDWill, je suis toujours à la recherche du cas où la clé "naturelle" vaut mieux que la substitution ...

D'autres articles traitant de ce problème font généralement référence à la théorie des bases de données relationnelles et aux performances des bases de données. Un autre argument intéressant, toujours oublié dans ce cas, est lié à normalisation de table et productivité du code:

chaque fois que je crée une table, vais-je perdre du temps

  1. identifier sa clé primaire et ses caractéristiques physiques (type, taille)
  2. me souvenant de ces caractéristiques à chaque fois que je veux y faire référence dans mon code?
  3. expliquer mon choix PK aux autres développeurs de l'équipe?

Ma réponse est non à toutes ces questions:

  1. Je n'ai pas de temps à perdre à essayer d'identifier "la meilleure clé primaire" lorsque je traite une liste de personnes.
  2. Je ne veux pas me souvenir que la clé primaire de ma table "computer" est une chaîne de 64 caractères (Windows accepte-t-il autant de caractères pour un nom d'ordinateur?).
  3. Je ne veux pas expliquer mon choix à d'autres développeurs, où l'un d'eux dira finalement "Ouais mec, mais considérez que vous devez gérer des ordinateurs sur différents domaines? Cette chaîne de 64 caractères vous permet-elle de stocker le nom de domaine + le Nom de l'ordinateur?".

Donc, je travaille depuis cinq ans avec une règle très basique: chaque table (appelons-la 'myTable') a son premier champ appelé 'id_MyTable 'qui est de type uniqueIdentifier. Même si cette table prend en charge une relation "plusieurs-à-plusieurs", comme une table 'ComputerUser', où la combinaison de 'id_Computer' et 'id_User 'forme une clé primaire très acceptable, je préfère créer cette' id_ComputerUser 'étant un uniqueIdentifier, juste pour s'en tenir à la règle.

L'avantage majeur est que vous n'avez plus à vous soucier de l'utilisation de la clé primaire et/ou de la clé étrangère dans votre code. Une fois que vous avez le nom de la table, vous connaissez le nom et le type PK. Une fois que vous saurez quels liens sont implémentés dans votre modèle de données, vous connaîtrez le nom des clés étrangères disponibles dans la table.

Je ne suis pas sûr que ma règle soit la meilleure. Mais c'est une solution très efficace!

5

Une approche pratique pour développer une nouvelle architecture est celle qui utilise des clés de substitution pour les tables qui contiendront des milliers d'enregistrements multi-colonnes hautement uniques et des clés composites pour de courtes tables de description. Je trouve généralement que les collèges dictent l'utilisation de clés de substitution alors que les programmeurs du monde réel préfèrent les clés composites. Vous devez vraiment appliquer le bon type de clé primaire à la table - pas seulement dans un sens ou dans l'autre.

4
sbeamers

Je vais être court et gentil ici: les clés primaires composites ne sont pas bonnes de nos jours. Ajoutez des clés arbitraires de substitution si vous le pouvez et conservez les schémas de clés actuels via des contraintes uniques. ORM est heureux, vous êtes heureux, le programmeur original n'est pas si heureux, mais à moins qu'il ne soit votre patron, il peut simplement s'en occuper.

3
MattC

l'utilisation de clés naturelles fait un cauchemar en utilisant n'importe quel ORM automatique comme couche de persistance. De plus, les clés étrangères sur plusieurs colonnes ont tendance à se chevaucher, ce qui posera un problème supplémentaire lors de la navigation et de la mise à jour de la relation de manière OO.

Vous pouvez néanmoins transformer la clé naturelle en une contrainte unique et ajouter un identifiant généré automatiquement; cela n'élimine pas le problème des clés étrangères, cependant, celles-ci devront être changées à la main; j'espère que plusieurs colonnes et contraintes qui se chevauchent seront une minorité de toute la relation, vous pouvez donc vous concentrer sur la refactorisation là où cela compte le plus.

natural pk ont ​​leur scénario de motivation et d'utilisation et ne sont pas une mauvaise chose (tm), ils ont juste tendance à ne pas bien s'entendre avec ORM.

mon sentiment est que, comme tout autre concept, les clés naturelles et la normalisation de table devraient être utilisées lorsqu'elles sont raisonnables et non comme des contraintes de conception aveugles

3

Les clés composites peuvent être bonnes - elles peuvent affecter les performances - mais elles ne sont pas la seule réponse, de la même manière qu'une clé unique (de substitution) n'est pas la seule réponse.

Ce qui m'inquiète, c'est le manque de précision dans le raisonnement du choix des clés composites. Le plus souvent, l'imprécision sur quelque chose de technique indique un manque de compréhension - peut-être en suivant les directives de quelqu'un d'autre, dans un livre ou un article ...

Il n'y a rien de mal avec un seul ID unique - en fait, si vous avez une application connectée à un serveur de base de données et que vous pouvez choisir la base de données que vous utilisez, tout sera bon, et vous pouvez à peu près tout faire avec vos clés et pas vraiment trop souffrir.

Il y a eu et il y aura beaucoup d'écrits à ce sujet, car il n'y a pas de réponse unique. Il existe des méthodes et des approches qui doivent être appliquées avec soin et de manière compétente.

J'ai eu beaucoup de problèmes avec les identifiants fournis automatiquement par la base de données - et je les évite autant que possible, mais je les utilise encore occasionnellement.

2
Richard Harrison

Je ne suis pas expérimenté mais je suis toujours en faveur de l'utilisation de la clé primaire comme identifiant, voici l'explication à l'aide d'un exemple.

Le format des données externes peut changer avec le temps. Par exemple, vous pourriez penser que l'ISBN d'un livre constituerait une bonne clé primaire dans une table de livres. Après tout, les ISBN sont uniques. Mais alors que ce livre est en cours de rédaction, le secteur de l'édition aux États-Unis se prépare à un changement majeur, car des chiffres supplémentaires sont ajoutés à tous les ISBN. Si nous avions utilisé l'ISBN comme clé primaire dans un tableau de livres, nous devions mettre à jour chaque ligne pour refléter ce changement. Mais alors nous aurions un autre problème. Il y aura d'autres tables dans la base de données qui référencent des lignes dans la table books via la clé primaire. Nous ne pouvons pas modifier la clé dans le tableau des livres à moins que nous n'ayons d'abord examiné et mis à jour toutes ces références. Et cela impliquera la suppression des contraintes de clé étrangère, la mise à jour des tables, la mise à jour de la table des livres et enfin le rétablissement des contraintes. Dans l'ensemble, c'est une sorte de douleur. Les problèmes disparaissent si nous utilisons notre propre valeur interne comme clé primaire. Aucun tiers ne peut venir nous dire arbitrairement de changer notre schéma - nous contrôlons notre propre espace de clés. Et si quelque chose comme l'ISBN doit changer, il peut changer sans affecter aucune des relations existantes dans la base de données. En fait, nous avons découplé le tricotage des lignes de la représentation externe des données dans ces lignes.

Bien que l'explication soit assez livresque, je pense qu'elle explique les choses d'une manière plus simple.

2
Mohit Jain

... comment la base de données gère les champs ID de manière non efficace et quand elle crée des index, les tris d'arbres sont défectueux ...

C'était presque certainement un non-sens, mais cela pouvait être lié au problème de la contention de bloc d'index lors de l'attribution de numéros incrémentiels à un PK à un taux élevé à partir de différentes sessions. Si tel est le cas, l'index REVERSE KEY est là pour vous aider, mais au détriment d'une taille d'index plus grande en raison d'un changement d'algorithme de division par blocs. http://download.Oracle.com/docs/cd/B19306_01/server.102/b14220/schema.htm#sthref998

Optez pour le synthétique, en particulier si cela facilite un développement plus rapide avec votre ensemble d'outils.

2
David Aldridge

@JeremyDWill

Merci d'avoir apporté un équilibre indispensable au débat. En particulier, merci pour les informations sur DOMAINs.

J'utilise en fait des clés de substitution à l'échelle du système pour des raisons de cohérence, mais il y a sont des compromis impliqués. La cause la plus courante pour moi de maudire à l'aide de clés de substitution est lorsque j'ai une table de recherche avec une courte liste de valeurs canoniques - j'utiliserais moins d'espace et toutes mes requêtes seraient plus courtes/plus faciles/plus rapides si je venais de définir les valeurs le PK au lieu d'avoir à se joindre à la table.

1
Hank Gay

Vous pouvez faire les deux - étant donné que toute base de données de grande entreprise est susceptible d'être utilisée par plusieurs applications, y compris des administrateurs de base de données humains exécutant des requêtes ponctuelles et des importations de données, sa conception uniquement pour le bénéfice des systèmes ORM n'est pas toujours pratique ou souhaitable.

Ce que j'ai tendance à faire ces jours-ci, c'est d'ajouter une propriété "RowID" à chaque table - ce champ est un GUID, et donc unique à chaque ligne. Ce n'est PAS la clé primaire - c'est une clé naturelle (si possible). Cependant, toutes les couches ORM travaillant au-dessus de cette base de données peuvent utiliser le RowID pour identifier leurs objets dérivés.

Ainsi vous pourriez avoir:

 CREATE TABLE dbo.Invoice (
 CustomerId varchar (10), 
 CustomerOrderNo varchar (10), 
 InvoiceAmount money not null, 
 Commentaires nvarchar (4000), 
 RowId uniqueidentifier non nul par défaut (newid ()), 
 
 Clé primaire (CustomerId, CustomerOrderNo) 
) 

Ainsi, votre DBA est heureux, votre architecte ORM est heureux et l'intégrité de votre base de données est préservée!

1
Keith Williams

Je voulais juste ajouter quelque chose ici que je ne vois jamais couvert lors de la discussion des champs d'identité entiers générés automatiquement avec des bases de données relationnelles (parce que je les vois beaucoup), c'est-à-dire que son type de base peut déborder à un moment donné.

Maintenant, je n'essaye pas de dire que cela fait automatiquement des identifiants composites la voie à suivre, mais c'est juste un fait que même si plus de données pourraient être logiquement ajoutées à une table (qui est toujours unique), le seul entier généré automatiquement l'identité pourrait empêcher que cela se produise.

Oui, je me rends compte que dans la plupart des situations, c'est peu probable, et l'utilisation d'un entier de 64 bits vous donne beaucoup de marge de manœuvre, et de manière réaliste, la base de données aurait probablement dû être conçue différemment si un tel débordement se produisait.

Mais cela n'empêche pas quelqu'un de le faire ... une table utilisant un seul entier 32 bits généré automatiquement comme identité, qui devrait stocker toutes les transactions au niveau mondial pour une entreprise de restauration rapide en particulier, échouera car dès qu'il essaie d'insérer c'est 2 147 483 648e transaction (et c'est un scénario tout à fait réalisable).

C'est juste quelque chose à noter, que les gens ont tendance à ignorer ou à ignorer complètement. Si une table doit être insérée avec régularité, il faut tenir compte de la fréquence et de la quantité de données qui s'accumuleront au fil du temps, et si oui ou non un identifiant basé sur un entier doit être utilisé.

0
Xorcist