Mysql
 sql >> Base de données >  >> RDS >> Mysql

Mysql et le problème de FK

La ou les colonnes de clé étrangère doivent faire référence à une ou plusieurs colonnes comprenant un préfixe le plus à gauche de la clé primaire ou une clé unique dans la table parent.

En d'autres termes, les exemples suivants fonctionnent dans InnoDB :

CREATE TABLE Foo ( a INT, b INT, c INT, PRIMARY KEY (a,b,c) );
CREATE TABLE Bar ( x INT, y INT );

ALTER TABLE Bar ADD FOREIGN KEY (x,y) REFERENCES Foo(b,c); -- WRONG

ALTER TABLE Bar ADD FOREIGN KEY (x,y) REFERENCES Foo(a,c); -- WRONG

ALTER TABLE Bar ADD FOREIGN KEY (x,y) REFERENCES Foo(a,b); -- RIGHT

ALTER TABLE Bar ADD FOREIGN KEY (x) REFERENCES Foo(b); -- WRONG

ALTER TABLE Bar ADD FOREIGN KEY (x) REFERENCES Foo(a); -- RIGHT

Vous avez une erreur parce que vous essayez de faire l'équivalent de (x) références Foo(b).
Votre colonne codmenuitem est la deuxième des trois colonnes dans la clé primaire du parent.

Cela fonctionnerait si smenuitememp.codemenuitem devaient référencer smenuitem.codmodulo , car cette colonne est la colonne la plus à gauche dans la clé primaire de la table parent.

Concernant votre question de suivi :

Gardez à l'esprit le fonctionnement des clés étrangères. Chaque fois que vous insérez ou mettez à jour une ligne dans la table enfant, il doit rechercher une ligne dans la table parent pour vérifier que la valeur existe dans la colonne référencée. Si la colonne n'est pas indexée, elle devra effectuer une analyse de table pour réaliser cette recherche, et cela coûterait très cher, en supposant que votre table parent s'agrandisse.

Si vous essayez de rechercher une ligne basée sur la colonne du milieu d'un index multi-colonnes, l'index ne vous aide pas. Par analogie, c'est comme rechercher dans un annuaire téléphonique toutes les personnes portant un certain deuxième prénom.

Le SQL ANSI standard exige que la colonne référencée fasse partie d'une CLÉ PRIMAIRE ou d'une CLÉ UNIQUE, et il exige que les colonnes de clé étrangère correspondent à toutes les colonnes d'une contrainte primaire ou unique dans le parent.

Mais InnoDB est plus permissif. Il faut toujours que la colonne référencée dans la table parent soit indexée pour que la recherche soit efficace, et que les colonnes référencées soient les plus à gauche dans l'index. Mais un index non unique est correct; il est permis à une clé étrangère de le référencer.

Cela peut conduire à des cas étranges comme une ligne enfant qui référence plus d'une ligne dans le parent, mais on s'attend à ce que vous gériez de telles anomalies.

Je ressens le besoin d'insister sur le dernier point. Vous allez obtenir des données anormales si vous définissez des clés étrangères sur des colonnes indexées de manière non unique dans le parent. Cela entraînera probablement vos requêtes à signaler des lignes plusieurs fois lorsque vous effectuez des jointures. Vous ne devez pas utiliser ce comportement d'InnoDB ; vous devez définir des clés étrangères uniquement pour les colonnes parentes qui sont uniques.