Come disabilitare temporaneamente un vincolo di chiave esterna in MySQL?


651

È possibile disabilitare temporaneamente i vincoli in MySQL?

Ho due modelli Django, ognuno con una chiave straniera all'altro. L'eliminazione di istanze di un modello restituisce un errore a causa del vincolo ForeignKey:

cursor.execute("DELETE FROM myapp_item WHERE n = %s", n)
transaction.commit_unless_managed()  #a foreign key constraint fails here

cursor.execute("DELETE FROM myapp_style WHERE n = %s", n)
transaction.commit_unless_managed()

È possibile disabilitare temporaneamente i vincoli ed eliminare comunque?


3
O non capisco cosa vuoi fare, o quello che stai cercando di fare è molto, molto, molto brutto . Anche se puoi farlo, probabilmente non dovresti.
Dariusz,

3
Far cadere e riapplicare un FK sta cambiando il tuo db. Stai cercando di sfidare gli stessi vincoli che consentono al sistema di vedere un po 'di senso, non ha riguardo al fatto che un FK potrebbe essere una cosa temporanea, e se lo sapesse, sarebbe prendere dal panico.
Concedi Thomas

1
È strano quello che stai cercando di fare. Ma quale database stai usando?
andrefsp,

4
e se invece di disabilitare il tuo vincolo, lo avessi modificato in modo permanente ON DELETE SET NULL? Ciò compirebbe una cosa simile e non dovresti attivare e disattivare il controllo delle chiavi.
dnagirl

1
@dnagirl: sarebbe meglio, anzi. Come lo posso fare?
lug

Risposte:


1467

Prova DISABLE KEYSo

SET FOREIGN_KEY_CHECKS=0;

assicurati che

SET FOREIGN_KEY_CHECKS=1;

dopo.


14
è qualcosa che è impostato per mysql nel suo insieme o solo per quella sessione?
tipu,

28
Credo che sia per sessione.
Andrew Campbell,


1
Posso semplicemente disabilitare FOREIGN_KEY_CHECKS per una singola tabella?
jDub9,

@Pacerier Dalla lettura di ciò, sembra che puoi, ma solo per una singola sessione.
Brett,

150

Per disattivare il vincolo di chiave esterna a livello globale, attenere alla seguente procedura:

SET GLOBAL FOREIGN_KEY_CHECKS=0;

e ricordati di ripristinarlo quando hai finito

SET GLOBAL FOREIGN_KEY_CHECKS=1;

ATTENZIONE: eseguire questa operazione solo quando si esegue la manutenzione in modalità utente singolo. Come potrebbe comportare un'incoerenza dei dati. Ad esempio, sarà molto utile quando si carica una grande quantità di dati utilizzando un output mysqldump.


1
questo è quello che dovevo sapere, quindi non è una buona pratica, ma questa risposta di ragazzi dovrebbe segnare un punteggio più alto ...
ftrotter,

1
Questo ha funzionato per me dopo aver provato la "migliore risposta" non ha funzionato per me. Forse si potrebbe aggiungere una spiegazione della differenza.
hexnet,

7
@hexnet La differenza è che SET FOREIGN_KEY_CHECKScambia solo il valore per la connessione corrente , mentre SET GLOBAL ..cambia il valore per tutte le connessioni , comprese le connessioni future. Se lo fai solo SET FOREIGN..in una finestra, quindi prova ad applicare l'istruzione in una finestra diversa (su una connessione diversa), il valore non è cambiato lì. Con GLOBAL, la stessa variabile ha lo stesso valore per entrambe le connessioni.
MatsLindh,

L'unica cosa che potrebbe aiutarmi quando si riproduce un dump più grande (6+ GB) <3
Max

Questo non funziona per me. Quando provo, vedo:ERROR 1228 (HY000): Variable 'foreign_key_checks' is a SESSION variable and can't be used with SET GLOBAL
Mike B,

53

Normalmente disabilito i vincoli di chiave esterna quando voglio troncare una tabella, e poiché continuo a tornare a questa risposta, questo è per me futuro:

SET FOREIGN_KEY_CHECKS=0;
TRUNCATE TABLE table;
SET FOREIGN_KEY_CHECKS=1;

25

Invece di disabilitare il tuo vincolo, modificalo permanentemente su ON DELETE SET NULL. Ciò compirà una cosa simile e non dovresti attivare e disattivare il controllo delle chiavi. Così:

ALTER TABLE tablename1 DROP FOREIGN KEY fk_name1; //get rid of current constraints
ALTER TABLE tablename2 DROP FOREIGN KEY fk_name2;

ALTER TABLE tablename1 
  ADD FOREIGN KEY (table2_id) 
        REFERENCES table2(id)
        ON DELETE SET NULL  //add back constraint

ALTER TABLE tablename2 
  ADD FOREIGN KEY (table1_id) 
        REFERENCES table1(id)
        ON DELETE SET NULL //add back other constraint

Leggi questo ( http://dev.mysql.com/doc/refman/5.5/en/alter-table.html ) e questo ( http://dev.mysql.com/doc/refman/5.5/en) /create-table-foreign-keys.html ).


7
Attenzione, la modifica della tabella può richiedere molto tempo, meglio impostare il server globale su FOREIGN_KEY_CHECKS0 e rimetterlo una volta terminato il lavoro sporco. Inoltre potrebbe bloccarsi per scrivere i tuoi tavoli.
Aki,

Questo non spezzerà il riferimento quando si modifica il tipo di colonna remota? (Sembra che il mio cliente rinomina una tabella temporanea modificata con il nome originale della tabella.)
Cees Timmerman

15

Per disattivare il vincolo di chiave esterna a livello globale:

SET GLOBAL FOREIGN_KEY_CHECKS = 0;

e per vincolo di chiave esterna attiva

SET GLOBAL FOREIGN_KEY_CHECKS = 1;

10

Una soluzione molto semplice con phpmyadmin:

  • Nella tua tabella, vai alla SQLscheda
  • Dopo aver modificato il comando SQL che si desidera eseguire, accanto c'è una casella di controllo GO, denominata " Abilita controlli chiave esterna" .
  • Deseleziona questa casella di controllo ed esegui il tuo SQL . Sarà ricontrollato automaticamente dopo l'esecuzione.

3
Grazie! Infatti la soluzione SET FOREIGN_KEY_CHECKS=0; ..... SET FOREIGN_KEY_CHECKS=1;non ha funzionato per me in PHPMyAdmin perché ho dimenticato di deselezionare la casella di controllo "Abilita controlli chiave esterna". In PHPMyAdmin puoi saltare questi comandi SET e deselezionare la casella di controllo.
Jan

5

Per me SET FOREIGN_KEY_CHECKS=0;non era abbastanza. Stavo ancora avendo un com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException.

Ho dovuto aggiungere ALTER TABLE myTable DISABLE KEYS;.

Così:

SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE myTable DISABLE KEYS;
DELETE FROM myTable;
ALTER TABLE myTable ENABLE KEYS;
SET FOREIGN_KEY_CHECKS=1;

Cordiali saluti, mySQL 5.7 genera un avviso, il motore InnoDB non ha questa opzione quando si esegue il comando DISABLE KEYS.
jDub9,

questo ha funzionato, senza l'alter table non ha funzionato anche per me
David Kabii,

3

Se il campo chiave è nullable, è inoltre possibile impostare il valore su null prima di tentare di eliminarlo:

cursor.execute("UPDATE myapp_item SET myapp_style_id = NULL WHERE n = %s", n)
transaction.commit_unless_managed() 

cursor.execute("UPDATE myapp_style SET myapp_item_id = NULL WHERE n = %s", n)
transaction.commit_unless_managed()

cursor.execute("DELETE FROM myapp_item WHERE n = %s", n)
transaction.commit_unless_managed()

cursor.execute("DELETE FROM myapp_style WHERE n = %s", n)
transaction.commit_unless_managed()

2

In phpMyAdmin è possibile selezionare più righe, quindi fare clic sull'azione di eliminazione. Si accederà a una schermata in cui sono elencate le query di eliminazione, è possibile deselezionare il controllo chiave esterna e fare clic su Sì per eseguirle.

Ciò consentirà di eliminare le righe anche se esiste un vincolo di restrizione ON DELETE.


-2

Non è una buona idea impostare un vincolo di chiave esterna su 0, perché se lo fai, il tuo database non assicurerebbe che non stia violando l'integrità referenziale. Ciò potrebbe portare a dati inaccurati, fuorvianti o incompleti.

È possibile creare una chiave esterna per un motivo: poiché tutti i valori nella colonna figlio devono essere uguali a quelli nella colonna padre. Se non ci sono vincoli di chiave esterna, una riga figlio può avere un valore che non si trova nella riga padre, il che porterebbe a dati imprecisi.

Ad esempio, supponiamo che tu abbia un sito web per gli studenti per accedere e ogni studente deve registrarsi per un account come utente. Hai una tabella per gli ID utente, con ID utente come chiave primaria; e un'altra tabella per gli account degli studenti, con ID studente come colonna. Poiché ogni studente deve avere un ID utente, sarebbe logico rendere l'ID studente dalla tabella dei conti degli studenti una chiave esterna che faccia riferimento all'ID utente della chiave primaria nella tabella degli ID utente. Se non ci sono controlli di chiave esterna, uno studente potrebbe finire con un ID studente e nessun ID utente, il che significa che uno studente può ottenere un account senza essere un utente, il che è sbagliato.

Immagina se succede a una grande quantità di dati. Ecco perché è necessario il controllo della chiave esterna.

È meglio capire cosa sta causando l'errore. Molto probabilmente, stai tentando di eliminare da una riga padre senza eliminare da una riga figlio. Prova a eliminare dalla riga figlio prima di eliminare dalla riga padre.


È vero, c'è sempre un compromesso.
Pacerier,

21
Nessuno sta dicendo di eseguirlo in questo modo per sempre. Disattiva i vincoli, carica in blocco alcuni dati e li riaccendi. Non è un grosso problema, la gente lo fa sempre.
bwawok,

è necessario per le importazioni all'ingrosso, almeno per le prestazioni, è molto comune. inoltre a volte hai solo bisogno di ripristinare i dati, quindi puoi effettuare i controlli.
Firas Abd Alrahman,

3
Questa non è una risposta alla domanda.
Koray Tugay,

Nota, la sua domanda è come farlo temporaneamente. Ciò è necessario quando si eseguono determinate operazioni di manutenzione e importazione dei dati. L'avvertenza ovviamente è che i tuoi script di importazione diventano responsabili dell'integrità dei dati. Successivamente, quando gli indici e i vincoli vengono riattivati, il db ti dirà se qualcosa è rotto.
Mcstar
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.