Mysql
 sql >> Database >  >> RDS >> Mysql

Il problema di MySQL e FK

Le colonne della chiave esterna devono fare riferimento alle colonne che comprendono un prefisso all'estrema sinistra della chiave primaria o una chiave univoca nella tabella padre.

In altre parole, i seguenti esempi funzionano in 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

Hai ricevuto un errore perché stai tentando di eseguire l'equivalente di (x) riferimenti Foo(b).
La tua colonna codmenuitem è la seconda di tre colonne nella chiave primaria del genitore.

Funzionerebbe se smenuitememp.codemenuitem dovessero fare riferimento a smenuitem.codmodulo , perché quella colonna è la colonna più a sinistra nella chiave primaria della tabella padre.

Per la tua domanda di follow-up:

Tieni a mente il modo in cui funzionano le chiavi esterne. Ogni volta che inserisci o aggiorni una riga nella tabella figlio, è necessario cercare una riga nella tabella padre per verificare che il valore esista nella colonna di riferimento. Se la colonna non è indicizzata, sarà necessario eseguire una scansione della tabella per ottenere questa ricerca e ciò sarebbe molto costoso, supponendo che la tabella padre cresca.

Se provi a cercare una riga in base alla colonna centrale di un indice a più colonne, l'indice non ti aiuta. Per analogia, è come cercare in un elenco telefonico tutte le persone con un certo secondo nome.

Standard ANSI SQL richiede che la colonna di riferimento faccia parte di una CHIAVE PRIMARIA o CHIAVE UNICA e richiede che le colonne della chiave esterna corrispondano a tutte le colonne di un vincolo primario o univoco nel genitore.

Ma InnoDB è più permissivo. Richiede comunque che la colonna di riferimento nella tabella padre sia indicizzata in modo che la ricerca possa essere efficiente, e che le colonne di riferimento siano le più a sinistra nell'indice. Ma un indice non univoco va bene; è consentito che una chiave esterna vi faccia riferimento.

Questo può portare a casi strani come una riga figlio che fa riferimento a più di una riga nel genitore, ma ci si aspetta che gestirai tali anomalie.

Sento il bisogno di sottolineare l'ultimo punto. Tu farai ottenere dati anomali se si definiscono chiavi esterne in colonne non indicizzate in modo univoco nel genitore. Ciò probabilmente farà sì che le tue query riportino le righe più volte quando esegui i join. Non dovresti usare questo comportamento di InnoDB; dovresti definire le chiavi esterne solo per le colonne principali che sono univoche.