Wie kann ich eine Fremdschlüsseleinschränkung in MySQL vorübergehend deaktivieren?


651

Ist es möglich, Einschränkungen in MySQL vorübergehend zu deaktivieren?

Ich habe zwei Django-Modelle, jedes mit einem ForeignKey zum anderen. Das Löschen von Instanzen eines Modells gibt aufgrund der ForeignKey-Einschränkung einen Fehler zurück:

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()

Ist es möglich, Einschränkungen vorübergehend zu deaktivieren und trotzdem zu löschen?


3
Entweder verstehe ich nicht, was Sie tun möchten, oder was Sie versuchen, ist sehr, sehr, sehr hässlich . Selbst wenn Sie es schaffen, sollten Sie es wahrscheinlich nicht tun.
Dariusz

3
Dropping und erneute Anwendung ein FK ist Ihre db ändern. Sie versuchen, den Einschränkungen zu trotzen, die es dem System ermöglichen, einen Sinn zu erkennen. Es wird nicht berücksichtigt, dass eine FK eine vorübergehende Sache sein könnte, und wenn sie es wüsste, würde sie in Panik geraten.
Grant Thomas

1
Es ist seltsam, was du versuchst zu tun. Aber welche Datenbank verwenden Sie?
andrefsp

4
Was ist, wenn Sie Ihre Einschränkung nicht deaktiviert, sondern dauerhaft geändert haben ON DELETE SET NULL? Das würde eine ähnliche Sache bewirken und Sie müssten die Schlüsselüberprüfung nicht ein- und ausschalten.
Dnagirl

1
@dnagirl: das wäre in der Tat besser. Wie kann ich das machen?
Juli

Antworten:


1466

Versuchen Sie es DISABLE KEYSoder

SET FOREIGN_KEY_CHECKS=0;

stellen Sie sicher, dass

SET FOREIGN_KEY_CHECKS=1;

nach.


14
Ist dies etwas, das für MySQL als Ganzes oder nur für diese Sitzung festgelegt ist?
Tipu

28
Ich glaube, es ist pro Sitzung.
Andrew Campbell

13
serverfault.com/questions/291100/… , Beachten Sie auch, dass Sie nicht disable keys für Innodb
Pacerier

1
Kann ich FOREIGN_KEY_CHECKS nur für eine einzelne Tabelle deaktivieren?
jDub9

@Pacerier Nach dem Lesen scheint dies möglich zu sein, jedoch nur für eine einzelne Sitzung.
Brett

150

Gehen Sie wie folgt vor, um die Fremdschlüsseleinschränkung global zu deaktivieren:

SET GLOBAL FOREIGN_KEY_CHECKS=0;

und denken Sie daran, es zurückzusetzen, wenn Sie fertig sind

SET GLOBAL FOREIGN_KEY_CHECKS=1;

WARNUNG: Sie sollten dies nur tun, wenn Sie die Wartung im Einzelbenutzermodus durchführen. Dies könnte zu Dateninkonsistenzen führen. Dies ist beispielsweise sehr hilfreich, wenn Sie eine große Datenmenge mit einer mysqldump-Ausgabe hochladen.


1
Das ist, was ich wissen musste, also ist es keine großartige Übung, aber diese Antwort sollte höher sein ...
ftrotter

1
Dies funktionierte für mich, nachdem ich versucht hatte, die 'beste Antwort' zu finden. Vielleicht könnte eine Erklärung des Unterschieds hinzugefügt werden.
Hexnet

7
@hexnet Der Unterschied besteht darin, dass nur SET FOREIGN_KEY_CHECKSder Wert für die aktuelle VerbindungSET GLOBAL .. geändert wird , während der Wert für alle Verbindungen , einschließlich zukünftiger Verbindungen , geändert wird . Wenn Sie dies nur SET FOREIGN..in einem Fenster tun , versuchen Sie, die Anweisung in einem anderen Fenster (über eine andere Verbindung) anzuwenden. Der Wert hat sich dort nicht geändert. Mit GLOBALhat dieselbe Variable für beide Verbindungen den gleichen Wert.
MatsLindh

Das einzige, was mir bei der Wiedergabe eines größeren Dumps (6+ GB) <3 helfen könnte
Max

Das funktioniert bei mir nicht. Wenn ich es versuche, sehe ich:ERROR 1228 (HY000): Variable 'foreign_key_checks' is a SESSION variable and can't be used with SET GLOBAL
Mike B

53

Normalerweise deaktiviere ich Fremdschlüsseleinschränkungen nur, wenn ich eine Tabelle abschneiden möchte, und da ich immer wieder auf diese Antwort zurückkomme, ist dies für die Zukunft für mich:

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

25

Anstatt Ihre Einschränkung zu deaktivieren, ändern Sie sie dauerhaft in ON DELETE SET NULL. Damit wird eine ähnliche Sache erreicht, und Sie müssten die Schlüsselüberprüfung nicht ein- und ausschalten. Wie so:

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

Lesen Sie dies ( http://dev.mysql.com/doc/refman/5.5/en/alter-table.html ) und dieses ( http://dev.mysql.com/doc/refman/5.5/en) /create-table-foreign-keys.html ).


7
Beachten Sie, dass das Ändern der Tabelle sehr lange dauern kann. Es ist besser, den Server global FOREIGN_KEY_CHECKSauf 0 zu setzen und ihn nach Abschluss der Drecksarbeit wieder zurückzusetzen. Außerdem könnte es für das Schreiben Ihrer Tabellen gesperrt werden.
Aki

Wird die Referenz beim Ändern des Remote-Spaltentyps nicht beschädigt? (Es scheint, dass mein Client eine modifizierte temporäre Tabelle in den ursprünglichen Tabellennamen
Cees Timmerman

15

So deaktivieren Sie die Fremdschlüsseleinschränkung global:

SET GLOBAL FOREIGN_KEY_CHECKS = 0;

und für aktive Fremdschlüsseleinschränkung

SET GLOBAL FOREIGN_KEY_CHECKS = 1;

10

Eine sehr einfache Lösung mit phpmyadmin:

  • Gehen Sie in Ihrer Tabelle zur SQLRegisterkarte
  • Nachdem Sie den SQL - Befehl bearbeiten , dass Sie ausführen möchten, gibt es ein Kontrollkästchen neben dem GONamen ‚ aktivieren Fremdschlüsselprüfungen‘ .
  • Deaktivieren Sie dieses Kontrollkästchen und führen Sie SQL aus . Es wird nach der Ausführung automatisch erneut überprüft.

3
Vielen Dank! In der Tat hat die Lösung SET FOREIGN_KEY_CHECKS=0; ..... SET FOREIGN_KEY_CHECKS=1;in PHPMyAdmin nicht funktioniert, da ich vergessen habe, das Kontrollkästchen "Fremdschlüsselprüfungen aktivieren" zu deaktivieren. In PHPMyAdmin können Sie diese SET-Befehle überspringen und einfach das Kontrollkästchen deaktivieren.
Jan

5

Für mich war das einfach SET FOREIGN_KEY_CHECKS=0;nicht genug. Ich hatte immer noch eine com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException.

Ich musste hinzufügen ALTER TABLE myTable DISABLE KEYS;.

Damit:

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

Zu Ihrer Information, mySQL 5.7 gibt eine Warnung aus. Die InnoDB-Engine verfügt nicht über diese Option, wenn der Befehl DISABLE KEYS ausgeführt wird.
jDub9

das hat funktioniert, ohne den alter table hat es auch bei mir nicht funktioniert
David Kabii

3

Wenn das Schlüsselfeld nullbar ist, können Sie den Wert auch auf null setzen, bevor Sie versuchen, ihn zu löschen:

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 können Sie mehrere Zeilen auswählen und dann auf die Löschaktion klicken. Sie gelangen auf einen Bildschirm, in dem die Löschabfragen aufgelistet sind. Sie können die Überprüfung des Fremdschlüssels deaktivieren und auf Ja klicken, um sie auszuführen.

Auf diese Weise können Sie Zeilen löschen, auch wenn die Einschränkung ON DELETE vorliegt.


-2

Es ist keine gute Idee, eine Fremdschlüsseleinschränkung auf 0 zu setzen, da Ihre Datenbank sonst nicht sicherstellen würde, dass die referenzielle Integrität nicht verletzt wird. Dies kann zu ungenauen, irreführenden oder unvollständigen Daten führen.

Sie erstellen einen Fremdschlüssel aus einem Grund: Alle Werte in der untergeordneten Spalte müssen mit einem Wert in der übergeordneten Spalte übereinstimmen. Wenn es keine Fremdschlüsseleinschränkungen gibt, kann eine untergeordnete Zeile einen Wert haben, der sich nicht in der übergeordneten Zeile befindet, was zu ungenauen Daten führen würde.

Angenommen, Sie haben eine Website, auf der sich Schüler anmelden können, und jeder Schüler muss sich für ein Konto als Benutzer registrieren. Sie haben eine Tabelle für Benutzer-IDs mit der Benutzer-ID als Primärschlüssel. und eine weitere Tabelle für Studentenkonten mit der Studenten-ID als Spalte. Da jeder Schüler eine Benutzer-ID haben muss, ist es sinnvoll, die Schüler-ID aus der Schülerkonten-Tabelle zu einem Fremdschlüssel zu machen, der auf die Primärschlüssel-Benutzer-ID in der Benutzer-ID-Tabelle verweist. Wenn keine Fremdschlüsselprüfungen durchgeführt werden, hat ein Schüler möglicherweise eine Schüler-ID und keine Benutzer-ID. Dies bedeutet, dass ein Schüler ein Konto erhalten kann, ohne ein Benutzer zu sein, was falsch ist.

Stellen Sie sich vor, es passiert mit einer großen Datenmenge. Deshalb benötigen Sie die Fremdschlüsselprüfung.

Es ist am besten herauszufinden, was den Fehler verursacht. Höchstwahrscheinlich versuchen Sie, aus einer übergeordneten Zeile zu löschen, ohne aus einer untergeordneten Zeile zu löschen. Versuchen Sie, aus der untergeordneten Zeile zu löschen, bevor Sie aus der übergeordneten Zeile löschen.


Es stimmt, es gibt immer einen Kompromiss.
Pacerier

21
Niemand sagt, es für immer so laufen zu lassen. Sie deaktivieren Einschränkungen, laden einige Daten in großen Mengen und schalten sie wieder ein. Keine große Sache, die Leute machen es die ganze Zeit.
Bwawok

es ist für Massenimporte notwendig, zumindest für die Leistung ist es sehr häufig. Manchmal müssen die Daten nur wiederhergestellt werden, dann können Sie Ihre Überprüfungen durchführen.
Firas Abd Alrahman

3
Dies ist keine Antwort auf die Frage.
Koray Tugay

Beachten Sie, seine Frage ist, wie dies vorübergehend zu tun ist. Dies ist erforderlich, wenn bestimmte Wartungs- und Datenimporte durchgeführt werden. Die Einschränkung ist natürlich, dass Ihre Importskripte für die Datenintegrität verantwortlich werden. Später, wenn die Indizes und Einschränkungen wieder aktiviert werden, teilt Ihnen die Datenbank mit, ob etwas nicht funktioniert.
Mcstar
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.