Nécessité d'une clé étrangère dans ce cas (innoDB / mysql)
-
05-07-2019 - |
Question
J'ai récemment migré toute ma base de données de myisam vers innodb. Je suis assez nouveau dans tout cela, alors j’ai une question concernant l’utilisation de la clé étrangère.
Disons que j'ai deux tables: les utilisateurs et les messages.
utilisateurs
id (pr_key)
nom
messages
id (pr_key)
id_utilisateur
message
Les champs id sont tous les deux incrémentés automatiquement.
Alors maintenant, dans mes requêtes, je joins déjà ces 2 tables. Est-il encore nécessaire de placer une clé étrangère ici, je ne vois pas de point. At-il des avantages en termes de performances?
Si je choisis de mettre une clé étrangère ici, je suppose que je dois créer le pr_key des messages id et user_id.
L'ajout de l'autre prim_key ne prendra pas seulement plus d'espace, ce qui ralentira les performances.
Maintenant, si la table a deux pr_keys, et que je ne demande que sur l’une d’elles, aurai-je les mêmes avantages en termes de performances. Ou dois-je utiliser explicitement les deux clés?
Je sais que dans cet exemple, je rechercherai user_id. Il est donc peut-être judicieux de l'indexer de toute façon. Mais que se passe-t-il si le champ est un champ sur lequel il n'y a pas de recherche? Est-il toujours bon de placer une clé primaire multiple sur ce champ, uniquement pour la relation étrangère?
Merci!
La solution
Il présente les avantages de l'intégrité des données .
cela empêchera le code de l'application d'entrer l'utilisateur_id de 1234 dans la table de messages lorsqu'il n'y a pas d'utilisateur avec id = 1234 dans la table d'utilisateurs. Et cela empêchera l'application de supprimer l'utilisateur lorsque l'utilisateur a des messages dans la table des messages.
Le nom de la PK ne doit pas nécessairement correspondre au nom de FK dans la table enfant de référence.
"Si je choisis de mettre une clé étrangère ici, je suppose que je dois créer le pr_key des messages id et user_id. "
NON . Vous ne modifiez pas la clé dans la table des messages, vous établissez simplement une contrainte de clé étrangère (FK) sur la colonne User_Id de la table des messages, qui référence (pointe vers) la colonne id de la table des utilisateurs. Aucune PK supplémentaire n'est requise dans les messages, et comme la PK est déjà unique (vous ne pouvez pas avoir deux messages avec le même messageId), la PK à la fois sur id et user_id ne peut plus ajouter d'unicité.
En résumé, vous pouvez avoir une idée fausse fondamentale sur ce que sont réellement une clé primaire et une clé étrangère.
- Une PK est une contrainte sur l'unicité d'une ligne, elle nécessite un index.
- Un FK est une contrainte sur la valeur d'une colonne (il spécifie que la valeur existe en tant que valeur PK dans une autre table référencée). Elle ne pas nécessite un index.
@Noah, consultez cette autre question SO
Autres conseils
Que vous établissiez ou non une règle FOREIGN KEY formelle sur les messages (user_id), le fait est qu’il s’agit d’une relation de clé étrangère.
Tout d’abord, rappelez-vous qu’une clé primaire appropriée sur une table devrait suffire à identifier de manière unique chaque enregistrement de la table. Étant donné que chaque message contient déjà le champ id
, vous ne souhaitez pas non plus insérer le id_utilisateur
dans la clé primaire de la table des messages.
Deuxièmement, comme Charles l'a déjà indiqué en déclarant une FOREIGN KEY sur les messages (user_id), les utilisateurs de REFERENCES (id) vous permettront de garantir l'intégrité de vos données. À l'aide d'une contrainte de clé étrangère, vous pouvez spécifier l'action à exécuter lorsqu'un enregistrement de la table des utilisateurs contenant les enregistrements correspondants dans la table des messages est supprimé. Vos choix sont ON DELETE CASCADE (supprimez tous les enregistrements enfants de cet enregistrement utilisateur), ON DELETE RESTRICT (n'autorisez pas la suppression d'un utilisateur possédant des enregistrements dans la table des messages), ON DELETE NO ACTION (ignore les opérations de suppression) , ON DELETE SET NULL (conserve les enregistrements enfants mais définit le champ user_id sur NULL).
Chacune de ces options est appropriée en fonction des circonstances, mais le plus important est de pouvoir empêcher les pointeurs null inattendus de la table enfant à la table parent.
Troisièmement, l’établissement de la relation FOREIGN KEY générera des gains de performances car il générera un INDEX sur les messages (user_id) qui correspond à PRIMARY KEY sur la table users. Lorsque vous effectuez une requête qui associe ces champs, vous constaterez que le nombre d’enregistrements devant être interrogés pour renvoyer les enregistrements enfants est considérablement réduit par rapport au fait que la clé étrangère n’a pas été établie.
@Charles Bretana - La question à laquelle vous vous connectez est spécifique à Microsoft SQL Server. La question ici concerne MySQL / InnoDB.
Je vous recommande de consulter la documentation de Contraintes de clés étrangères InnoDB .
InnoDB requiert des index sur les devises étrangères. clés et clés référencées afin que les contrôles de clé étrangère peuvent être rapides et non besoin d'un scan de table. dans le table de référencement, il doit y avoir un index où les colonnes de clé étrangère sont répertoriés comme les premières colonnes du même ordre. Un tel index est créé sur la table de référencement automatiquement si ça n'existe pas. (Ceci est en contrairement à certaines versions plus anciennes, quels index devaient être créés explicitement ou la création de l'étranger les contraintes clés échoueraient.) nom_index, s'il est indiqué, est utilisé comme décrit précédemment.