Dois-je utiliser des clés primaires à plusieurs colonnes ou ajouter une nouvelle colonne?

15

Ma conception de base de données actuelle utilise une clé primaire à plusieurs colonnes pour utiliser les données existantes (qui seraient de toute façon uniques) au lieu de créer une colonne supplémentaire attribuant à chaque entrée une clé arbitraire. Je sais que cela est autorisé, mais je me demandais si c'est une pratique que je pourrais vouloir utiliser avec prudence et éventuellement éviter (un peu comme goto en C).

Quels sont donc certains des inconvénients que je pourrais voir dans cette approche ou les raisons pour lesquelles je voudrais une clé de colonne unique?

Covar
la source
2
Je sais pas, je pense que cela aurait été mieux sur SO.
FrustratedWithFormsDesigner
2
@FrustratedWithFormsDesigner Cela pourrait aller à SO, mais je pense que cela fonctionne ici aussi, car la question semble se concentrer sur "quels sont les avantages et les inconvénients de cette approche" plutôt que "comment faire X?".
Adam Lear
@Anna Lear ♦: C'est un "pour et un contre" des décisions de conception qui auront un impact direct et certain sur le codage, donc je pense que SO serait un meilleur endroit.
FrustratedWithFormsDesigner

Réponses:

8

Habituellement, lorsque vous avez une table avec une clé primaire à plusieurs colonnes, c'est le résultat d'une table de jointure (plusieurs à plusieurs) qui est devenue élevée pour être sa propre entité (et mérite donc sa propre clé primaire). Nombreux sont ceux qui soutiennent que toute table de jointure DEVRAIT être une entité par défaut, mais c'est une discussion pour un autre jour.

Regardons une relation hypothétique de plusieurs à plusieurs:

Étudiant * --- * Classe

(Un étudiant peut être dans plusieurs classes, une classe peut avoir plusieurs étudiants).

Entre ces deux tables se trouvera une table de jonction appelée StudentClass (ou ClassStudent selon la façon dont vous l'écrivez). Parfois, vous voulez garder une trace de choses comme lorsque l'élève était en classe. Vous l'ajouterez donc à la table StudentClass. À ce stade, StudentClass est devenu une entité unique ... et devrait recevoir un nom pour le reconnaître comme tel, par exemple l'inscription.

Étudiant 1 --- * Inscription * --- 1 classe

(un étudiant peut avoir plusieurs inscriptions, chaque inscription est pour une classe (ou dans le sens contraire, une classe peut avoir plusieurs inscriptions, chaque inscription est pour un étudiant).

Maintenant, vous pouvez interroger des choses comme, combien d'étudiants étaient inscrits dans la classe de chimie 101 cette dernière année? Ou dans quelles classes l'étudiant John Doe était-il inscrit pendant ses études à l'Université Acme? Cela était possible sans la clé primaire séparée, mais une fois que vous avez une clé primaire pour l'inscription, une requête plus facile serait de ces inscriptions (par id), combien d'étudiants ont reçu une note de passage?

La détermination de savoir si une entité mérite un PK se résume à combien de requêtes (ou de manipulations) vous ferez pour cette entité. Supposons, par exemple, que vous vouliez joindre les devoirs terminés pour un élève d'une classe. L'endroit logique pour attacher cette entité (affectation) serait sur l'entité d'inscription. Donner à l'inscription sa propre clé primaire rendrait les requêtes d'affectation plus simples.

Michael Brown
la source
1
Vous l'ajouterez donc à la table StudentClass. À ce stade, StudentClass est devenu une entité unique ... et devrait recevoir un nom pour le reconnaître comme tel, par exemple l'inscription. C'est tellement simple, mais cela a tellement de valeur!
Botis
8

Il est logique d'avoir une colonne id distincte. Lorsque vous souhaitez obtenir quelque chose de votre table de base de données, il est plus facile de le faire:

SELECT whatever FROM table WHERE id=13

que SELECT quoi que ce soit DE la table O WH col1 = 'val1' ET col2 = 'val2' ET col3 = 'val3'

Par exemple, dans une application Web, cela se traduit par une URL ressemblant à ceci:

www.somewebsite.com/somepage.php?id=13

ou comme ça:

www.somewebsite.com/somepage.php?col1=val1&col2=val2&col3=val3
infrarouge
la source
4
Et il est beaucoup plus facile d'ajouter une table associée lorsque vous pouvez lier sur un ID, au lieu de plusieurs colonnes
CaffGeek
3
Désolé, à ce stade, je dois -1, car A) ce n'est pas noir et blanc. L'ajout d'une colonne ID s'accompagne de points négatifs tels que l'endroit et le moment où vous générez ce nouvel ID. De plus, cela pourrait entraîner des jointures ou des SELECTrequêtes supplémentaires . Et, B) , je n'ai aucune idée de la façon dont cela provoque réellement tout type d'exigence d'URL (sauf si vous travaillez avec un mauvais cadre). Mes URL ne contiennent aucune chaîne de requête ?id=13, encore moins ?col1=val1&col2=val2&col3=val3.
Nicole
2
@renesis: Ce site a des questions et des utilisateurs uniques, qui se trouvent dans les URL. Cependant, il s'agit en quelque sorte d'un cas spécial, car ces données particulières ne changent pas.
Michael K
1
@Renesis, la plupart (peut-être toutes) des bases de données modernes ont des types de colonnes entiers auto_increment qui peuvent générer les ID automatiquement et en toute sécurité, et les rapporter via une requête SQL ou un appel de fonction de bibliothèque. Ou dans un environnement distribué, vous utilisez un grand hachage aléatoire. Certaines bases de données créeront même une colonne d'ID masquée pour vous si vous n'en avez pas déjà une dans le tableau.
GrandmasterB
@Michael - Je n'ai pas dit que les identifiants ne sont jamais dans les URL. Bien sûr qu'ils le sont. Si vous avez des URL qui représentent une ligne de données, alors oui, ces données devraient probablement avoir un ID unique. Sauf si une autre partie de l'URL fournit déjà les autres parties du multi-clé. @GrandmasterB Aucune des deux dernières entreprises pour lesquelles j'ai travaillé (plus de 6 ans), qui utilisent toutes les deux MySQL (l'une prenant également en charge Oracle et SQL Server), n'a pu utiliser l'auto-incrémentation, ni un grand hachage aléatoire.
Nicole
8

Fondamentalement, vous demandez si vous devez utiliser des clés de substitution ou naturelles (dans votre cas, cela ressemble à des clés naturelles composites ). Voici un excellent article: http://www.agiledata.org/essays/keys.html

Je préfère les clés de substitution car elles simplifient l'administration au cours de la vie de la base de données (vous n'avez jamais à vous soucier de l'implication des clés qui changent de sens, ce qui ne devrait jamais se produire mais se produit dans tout système réel où les humains sont impliqués). Cependant , s'il y a beaucoup de tables de "recherche" dans la base de données (c'est-à-dire des tables qui sont essentiellement des paires clé: valeur), les clés de substitution peuvent devenir encombrantes car vous devez joindre ces tables dans la requête afin d'obtenir des résultats significatifs.

Par exemple, supposons que vous ayez deux entités: Adresse et Pays.

  • La relation est: Adresse * ----- 1 Pays
  • L'entité Pays est essentiellement une clé: paire de valeurs (par exemple, États-Unis: États-Unis, CA: Canada, MX: Mexique, etc.)
  • Pour interroger cette structure pour toutes les adresses aux États-Unis:

select * from Address where CountryCode = 'US'

  • Pour effectuer la même requête avec des clés de substitution:

select Address.* from Address join Country on Address.CountryID = Country.ID where Country.Code = 'US'

Je suis à l'aise d'imposer des clés naturelles pour les tables de recherche et des clés de substitution pour tout le reste, si je suis sûr que les clés naturelles ne changeront pas trop souvent, voire jamais.

Curtis Batt
la source
5

Cela dépend de la façon dont vous accédez aux données. Si vous effectuez de nombreuses recherches de clés partielles (où vous sélectionnez des enregistrements en fonction, disons, seulement de deux des trois clés), vous souhaiterez conserver les clés en plusieurs parties. OTOH, si vous avez beaucoup de relations 1: 1 avec d'autres tables, il est probablement plus logique d'avoir une clé de substitution.

TMN
la source
1

J'aime toujours avoir une clé primaire de substitution pour chaque table. Mais il n'y a pas beaucoup de raisons "dures" pour faire respecter cela que j'ai entendu.

La seule fois où j'ai eu une morsure de clé naturelle à plusieurs colonnes, c'était avec ORM. Parfois, je rencontrais des problèmes avec une clé primaire à plusieurs colonnes utilisant Linq To Entities.

Mike M.
la source
1

Ne dites jamais jamais, mais se joindre à 4 colonnes est une douleur. Plus vous avez de colonnes avec des données intelligentes, plus ces valeurs peuvent changer. Les bases de données peuvent être configurées pour maintenir l'intégrité référentielle avec des mises à jour en cascade.

Vous pouvez toujours créer un autre index pour gérer les valeurs uniques.

Les performances sont probablement négligeables dans la plupart des cas, mais vous pouvez tester vos requêtes avec et sans la clé de substitution.

JeffO
la source
0

J'ai du mal à trouver une bonne raison d'imposer une clé distincte, mais comme vous l'avez dit, beaucoup de gens l'ont insérée.

Je ne trouve pas cela utile (en particulier avec le stockage) lorsque je traite des tableaux de faits / détails. Exemple canonique d'une table de faits de vente avec une (clé_client, clé_produit, clé_produit) avec quantité n'a pas beaucoup de sens d'avoir une clé au niveau de l'enregistrement.

Jé Queue
la source
0

Avoir PK comme auto-incrémentation int réduit les tracas si vous constatez que votre clé composite peut en réalité avoir des doublons.

Paul Nathan
la source
0

Il y a une bonne discussion qui remonte à 2002 sur Ask Tom . C'est spécifique à Oracle, mais la discussion plus large est pertinente quelle que soit la base de données que vous utilisez.

Rhys Gibson
la source