Est-il correct d'avoir une clé étrangère comme clé primaire?


103

J'ai deux tables:

  • Utilisateur (nom d'utilisateur, mot de passe)
  • Profil (ID de profil, sexe, date de naissance, ...)

Actuellement, j'utilise cette approche: chaque enregistrement de profil a un champ nommé "userId" comme clé étrangère qui renvoie à la table User. Lorsqu'un utilisateur s'inscrit, son enregistrement de profil est automatiquement créé.

Je suis confus avec la suggestion de mon ami: avoir le champ "userId" comme clé étrangère et primaire et supprimer le champ "profileId". Quelle approche est la meilleure?


3
Entity Framework génère cela (avec le code en premier) pour les relations zeroOrOne (et un) -à-. Alors ... c'est possible. Est-ce la meilleure façon ... C'est une autre question. Mais c'est valable. Je n'ai jamais fait cela en créant mes propres bases de données (mais je n'y ai même jamais pensé).
Raphaël Althaus

Réponses:


132

Les clés étrangères sont presque toujours «Autoriser les doublons», ce qui les rendrait inadaptées en tant que clés primaires.

Au lieu de cela, recherchez un champ qui identifie de manière unique chaque enregistrement de la table ou ajoutez un nouveau champ (un entier à incrémentation automatique ou un GUID) pour agir en tant que clé primaire.

La seule exception à cela concerne les tables avec une relation un-à-un , où la clé étrangère et la clé primaire de la table liée sont identiques.


74
Une clé primaire composite qui se compose de deux clés étrangères est également parfaitement adaptée à l'implémentation de relations plusieurs-à-plusieurs.
droite le

1
@rezadru: Loin de moi l'idée d'être en désaccord avec rightfold, mais une clé de substitution est presque toujours un meilleur choix.
Robert Harvey

4
Rien à propos d'une clé étrangère n'indique qu'il s'agit d'un 1 à plusieurs (ou "autoriser les doublons" comme écrit). Les contraintes clés et l'unicité sont deux concepts distincts dans une base de données et peuvent facilement être mélangés tout aussi facilement que l'ajout d'un index (qui serait un troisième concept distinct).
blindguy le

40

Les clés primaires doivent toujours être uniques, les clés étrangères doivent autoriser des valeurs non uniques si la table est une relation un-à-plusieurs. Il est parfaitement acceptable d'utiliser une clé étrangère comme clé primaire si la table est connectée par une relation un-à-un, pas une relation un-à-plusieurs. Si vous souhaitez que le même enregistrement utilisateur ait la possibilité d'avoir plus d'un enregistrement de profil associé, utilisez une clé primaire distincte, sinon restez fidèle à ce que vous avez.


11

Oui, il est légal d'avoir une clé primaire comme clé étrangère. C'est une construction rare, mais elle s'applique pour:

  • une relation 1: 1. Les deux tables ne peuvent pas être fusionnées en une seule en raison des autorisations et des privilèges différents ne s'appliquent qu'au niveau de la table (à partir de 2017, une telle base de données serait étrange).

  • une relation 1: 0..1. Le profil peut exister ou non, selon le type d'utilisateur.

  • les performances sont un problème, et la conception agit comme une partition: la table de profil est rarement consultée, hébergée sur un disque séparé ou a une politique de partitionnement différente de celle de la table des utilisateurs. Cela n'aurait pas de sens si le stockage de soulignement est en forme de colonne.


Il y aurait une performance négative si les tables étaient jointes souvent, ce qui conduit à la recommandation normale qu'une table est meilleure. Dans certains cas, les données sont toujours accessibles séparément, non jointes, et il peut y avoir des avantages organisationnels à avoir deux tables avec une relation 1: 1.
blindguy le

4

Il est généralement considéré comme une mauvaise pratique d'avoir une relation individuelle. En effet, vous pouvez simplement avoir les données représentées dans une table et obtenir le même résultat.

Cependant, dans certains cas, vous ne pourrez peut-être pas apporter ces modifications à la table que vous référencez. Dans ce cas, il n'y a aucun problème à utiliser la clé étrangère comme clé primaire. Il peut être utile d'avoir une clé composite composée d'une clé primaire unique à incrémentation automatique et de la clé étrangère.

Je travaille actuellement sur un système où les utilisateurs peuvent se connecter et générer un code d'enregistrement à utiliser avec une application. Pour des raisons que je n'entrerai pas, je ne peux pas simplement ajouter les colonnes requises à la table des utilisateurs. Je vais donc un à un avec la table des codes.


2
Je suis généralement d'accord avec vous pour dire qu'il y a de nombreux avantages à avoir toutes les données dans le même tableau sous forme de colonnes supplémentaires. Bien que ce soit écrit .. "vous pourriez simplement avoir les données représentées dans une table et obtenir le même résultat" ..: avoir une table séparée peut être utile, par exemple ici si l'entrée de la table de profil est facultative. Par exemple, chaque client de la banque peut ne pas disposer d'un enregistrement bancaire en ligne. Dans ce cas, la table d'enregistrement IB pourrait être utilisée pour empêcher d'autres tables d'avoir d'autres enregistrements enfants. Là encore, cela pourrait être fait avec un nouveau PK pour la table d'enregistrement IB également.
Teddy

1
@Teddy De même, je suis généralement d'accord avec ce que vous avez dit. Cependant, dans la question d'origine, ils déclarent "... son enregistrement de profil est automatiquement créé ...", ce qui implique que la table de profil n'est pas facultative. Dans une situation où la table de profil était facultative, alors oui, l'avoir comme table séparée est faisable. Mais là encore, ils pourraient simplement utiliser des colonnes Nullable dans la même table.
Tshsmith

1
En utilisant une deuxième table séparée, nous pouvons empêcher l'entrée dans une troisième table qui n'est autorisée que pour les personnes qui ont une entrée dans la deuxième table.
Teddy

Absolument, mais si nous fusionnons les tables 1 à 1, nous pouvons empêcher les personnes avec des valeurs nulles d'accéder à la troisième table (techniquement la deuxième maintenant). Mais la question OP posée contient la ligne "... lors de l'inscription .. ... son enregistrement de profil est automatiquement créé ...", rendant cela redondant.
Tshsmith

Ma principale raison de considérer cela est que dans l'entreposage de données, il est recommandé de séparer les tables de faits et de dimension. Les tables de faits et de dimensions séparées sont des indices utiles lorsque vous travaillez avec des logiciels tels que PowerPivot, PowerBI et Tableau.
Marco Rosas

4

Oui, une clé étrangère peut être une clé primaire dans le cas d'une relation un à un entre ces tables


2
ceci est également utile pour la conception de sous-types de supertypes. La clé primaire des tables de sous-type doit être une référence de clé étrangère à la table de supertype.
axelioo

2

Je ne ferais pas ça. Je garderais la profileIDclé primaire de la tableProfile

Une clé étrangère n'est qu'une contrainte référentielle entre deux tables

On pourrait soutenir qu'une clé primaire est nécessaire comme cible de toute clé étrangère qui y fait référence à partir d'autres tables. Une clé étrangère est un ensemble d'une ou plusieurs colonnes dans n'importe quelle table (pas nécessairement une clé candidate, encore moins la clé primaire, de cette table) qui peut contenir la ou les valeurs trouvées dans la ou les colonnes de clé primaire de certains autre table. Nous devons donc avoir une clé primaire correspondant à la clé étrangère. Ou devons-nous? Le seul but de la clé primaire dans la paire clé primaire / clé étrangère est de fournir une jointure sans ambiguïté - pour maintenir l'intégrité référentielle par rapport à la table "étrangère" qui contient la clé primaire référencée. Cela garantit que la valeur à laquelle la clé étrangère fait référence sera toujours valide (ou nulle, si elle est autorisée).

http://www.aisintl.com/case/primary_and_foreign_key.html


1
Peut-être - si vous avez la contrainte FK entre User.UserID et Profile.UserID, alors il serait fortement recommandé d'avoir un index sur Profile.UserID. Pourquoi ne pas en faire l'index clusterisé principal sur le profil de table, en économisant un deuxième index et beaucoup de travail inutile pour le moteur de base de données?
Ingénieur inversé

1

Cela dépend de l'entreprise et du système.

Si votre userId est unique et le sera tout le temps, vous pouvez utiliser userId comme clé primaire. Mais si jamais vous souhaitez étendre votre système, cela rendra les choses difficiles. Je vous conseille d'ajouter une clé étrangère dans l'utilisateur de la table pour établir une relation avec le profil de la table au lieu d'ajouter une clé étrangère dans le profil de la table.


0

Réponse courte: DÉPEND .... Dans ce cas particulier, ça pourrait être bien. Cependant, les experts le déconseilleront à peu près à chaque fois; y compris votre cas.

Pourquoi?

Les clés sont rarement uniques dans les tables lorsqu'elles sont étrangères (provenant d'une autre table) à la table en question. Par exemple, un ID d'article peut être unique dans une table ITEMS, mais pas dans une table ORDERS, car le même type d'article existera probablement dans un autre ordre. De même, les ID de commande peuvent être uniques (peuvent) dans la table ORDERS, mais pas dans une autre table telle que ORDER_DETAILS où une commande avec plusieurs éléments de campagne peut exister et pour interroger un élément particulier dans une commande particulière, vous avez besoin de la concaténation de deux FK (order_id et item_id) comme PK pour cette table.

Je ne suis pas un expert en DB, mais si vous pouvez justifier logiquement d'avoir une valeur auto-générée comme PK, je le ferais. Si ce n'est pas pratique, alors une concaténation de deux FK (ou peut-être plus) pourrait servir de PK. MAIS, je ne peux penser à aucun cas où une seule valeur FK peut être justifiée comme PK.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.