Jak tymczasowo wyłączyć ograniczenie klucza obcego w MySQL?


651

Czy można tymczasowo wyłączyć ograniczenia w MySQL?

Mam dwa modele Django, każdy z kluczem ForeignKey do drugiego. Usunięcie instancji modelu zwraca błąd z powodu ograniczenia 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()

Czy mimo to można tymczasowo wyłączyć ograniczenia i je usunąć?


3
Albo nie rozumiem, co chcesz robić, albo to, co próbujesz zrobić, jest bardzo, bardzo, bardzo brzydkie . Nawet jeśli możesz to zrobić, prawdopodobnie nie powinieneś.
— Dariusz

3
Upuszczenie i ponowne zastosowanie FK powoduje zmianę bazy danych. Próbujesz przeciwstawić się takim ograniczeniom, które pozwalają systemowi dostrzec sens, nie ma znaczenia, że ​​FK może być czymś tymczasowym, a gdyby wiedział, wpadłby w panikę.
— Grant Thomas

1
Dziwne, co próbujesz zrobić. Ale jakiej bazy danych używasz?
— andrefsp

4
co jeśli zamiast wyłączyć ograniczenie, na stałe je zmodyfikowałeś ON DELETE SET NULL? Osiągnęłoby to podobną rzecz i nie musiałbyś włączać i wyłączać sprawdzania klucza.
— dnagirl

1
@dnagirl: rzeczywiście byłoby lepiej. Jak mogę to zrobić?
— lipiec

Odpowiedzi:


1466

Spróbuj DISABLE KEYSlub

SET FOREIGN_KEY_CHECKS=0;

Upewnij się

SET FOREIGN_KEY_CHECKS=1;

po.


14
czy jest to coś, co jest ustawione dla mysql jako całości czy tylko dla tej sesji?
— tipu

28
Wierzę, że to jest na sesję.
— Andrew Campbell,

13
serverfault.com/questions/291100/… , Należy również pamiętać, że nie można disable keys dla Innodb
— Pacerier

1
Czy mogę po prostu wyłączyć FOREIGN_KEY_CHECKS dla pojedynczego stołu?
— jDub9

@Pacerier Po przeczytaniu tego wydaje się, że możesz, ale tylko na jedną sesję.
— Brett

150

Aby globalnie wyłączyć ograniczenie klucza obcego, wykonaj następujące czynności:

SET GLOBAL FOREIGN_KEY_CHECKS=0;

i pamiętaj, aby ustawić go z powrotem, gdy skończysz

SET GLOBAL FOREIGN_KEY_CHECKS=1;

OSTRZEŻENIE: Powinieneś to zrobić tylko podczas konserwacji w trybie pojedynczego użytkownika. Może to spowodować niespójność danych. Na przykład będzie to bardzo pomocne, gdy przesyłasz dużą ilość danych przy użyciu wyjścia mysqldump.


1
to musiałem wiedzieć, więc nie jest to świetna praktyka, ale odpowiedź tych facetów powinna być lepsza ...
— ftrotter

1
To zadziałało dla mnie po wypróbowaniu „najlepszej odpowiedzi” nie działało dla mnie. Być może można by dodać wyjaśnienie różnicy.
— hexnet

7
@hexnet Różnica polega na tym, że po SET FOREIGN_KEY_CHECKSprostu zmienia wartość bieżącego połączenia , a SET GLOBAL ..zmienia wartość wszystkich połączeń , w tym przyszłych połączeń. Jeśli zrobisz to tylko SET FOREIGN..w jednym oknie, spróbuj zastosować instrukcję w innym oknie (przez inne połączenie), wartość się tam nie zmieniła. Z GLOBAL, ta sama zmienna ma tę samą wartość dla obu połączeń.
— MatsLindh

Jedyne, co może mi pomóc podczas odtwarzania większego zrzutu (6+ GB) <3
— Max

To mi nie działa. Kiedy próbuję, widzę:ERROR 1228 (HY000): Variable 'foreign_key_checks' is a SESSION variable and can't be used with SET GLOBAL
— Mike B

53

Zwykle wyłączam ograniczenia klucza obcego tylko wtedy, gdy chcę obciąć tabelę, a ponieważ wciąż wracam do tej odpowiedzi, to dla mnie w przyszłości:

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

25

Zamiast wyłączać ograniczenie, trwale zmodyfikuj je, aby WŁĄCZYĆ USUŃ NULL. Dzięki temu osiągniesz podobną rzecz i nie będziesz musiał włączać i wyłączać sprawdzania klucza. Tak jak:

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

Przeczytaj to ( http://dev.mysql.com/doc/refman/5.5/en/alter-table.html ) i to ( http://dev.mysql.com/doc/refman/5.5/en /create-table-foreign-keys.html ).


7
Strzeż się, że zmiana tabeli może zająć dużo czasu, lepiej ustawić globalny serwer na FOREIGN_KEY_CHECKS0 i odłożyć go z powrotem po wykonaniu brudnej roboty. Poza tym może zablokować pisanie twoich tabel.
— Aki

Czy to nie złamie referencji przy zmianie typu kolumny zdalnej? (Wygląda na to, że mój klient zmienia nazwę zmodyfikowanej tabeli tymczasowej na pierwotną nazwę tabeli.)
— Cees Timmerman

15

Aby wyłączyć ograniczenie klucza obcego globalnie:

SET GLOBAL FOREIGN_KEY_CHECKS = 0;

i dla aktywnego ograniczenia klucza obcego

SET GLOBAL FOREIGN_KEY_CHECKS = 1;

10

Bardzo proste rozwiązanie z phpmyadmin:

  • W tabeli przejdź do SQLkarty
  • Po edycji polecenia SQL, które chcesz uruchomić, obok pola wyboru o GOnazwie „ Włącz sprawdzanie klucza obcego” znajduje się pole wyboru .
  • Odznacz to pole wyboru i uruchom SQL . Zostanie on automatycznie ponownie sprawdzony po uruchomieniu.

3
Dzięki! Rzeczywiście rozwiązanie SET FOREIGN_KEY_CHECKS=0; ..... SET FOREIGN_KEY_CHECKS=1;nie działało dla mnie w PHPMyAdmin, ponieważ zapomniałem odznaczyć pole wyboru „Włącz sprawdzanie klucza obcego”. W PHPMyAdmin możesz pominąć te polecenia SET i po prostu odznaczyć pole wyboru.
— Jan

5

Dla mnie to po prostu SET FOREIGN_KEY_CHECKS=0;za mało. Nadal miałem com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException.

Musiałem dodać ALTER TABLE myTable DISABLE KEYS;.

Więc:

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

Do Twojej wiadomości, mySQL 5.7 generuje ostrzeżenie, silnik InnoDB nie ma tej opcji po uruchomieniu polecenia DISABLE KEYS.
— jDub9

to działało, bez tabeli zmian to też nie działało dla mnie
— David Kabii

3

Jeśli pole klucza ma wartość zerową, możesz również ustawić wartość null przed próbą jej usunięcia:

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

W phpMyAdmin możesz wybrać wiele wierszy, a następnie kliknąć akcję usuwania. Wejdziesz do ekranu z listą usuniętych zapytań, możesz odznaczyć zaznaczenie klucza obcego i kliknąć Tak, aby je wykonać.

Umożliwi to usunięcie wierszy, nawet jeśli istnieje ograniczenie ograniczenia ON DELETE.


-2

Ustawienie ograniczenia klucza obcego na 0 nie jest dobrym pomysłem, ponieważ jeśli tak zrobisz, baza danych nie upewni się, że nie narusza integralności referencyjnej. Może to prowadzić do niedokładnych, wprowadzających w błąd lub niekompletnych danych.

Tworzysz klucz obcy z jakiegoś powodu: ponieważ wszystkie wartości w kolumnie potomnej będą takie same jak wartość w kolumnie macierzystej. Jeśli nie ma ograniczeń klucza obcego, wiersz potomny może mieć wartość, która nie znajduje się w wierszu nadrzędnym, co może prowadzić do niedokładnych danych.

Załóżmy na przykład, że masz witrynę internetową, na której studenci mogą się zalogować, a każdy uczeń musi zarejestrować się jako konto. Masz jedną tabelę dla identyfikatorów użytkowników, z identyfikatorem użytkownika jako kluczem podstawowym; i kolejna tabela dla kont studentów, z identyfikatorem studenta jako kolumną. Ponieważ każdy uczeń musi mieć identyfikator użytkownika, sensowne byłoby, aby identyfikator studenta z tabeli kont studentów był kluczem obcym, który odwołuje się do identyfikatora użytkownika klucza podstawowego w tabeli identyfikatorów użytkowników. Jeśli nie ma sprawdzania klucza obcego, uczeń może mieć identyfikator studenta i identyfikator użytkownika, co oznacza, że ​​uczeń może uzyskać konto bez bycia użytkownikiem, co jest błędne.

Wyobraź sobie, że dzieje się to z dużą ilością danych. Dlatego potrzebujesz sprawdzenia klucza obcego.

Najlepiej dowiedzieć się, co powoduje błąd. Najprawdopodobniej próbujesz usunąć z wiersza nadrzędnego bez usuwania z wiersza podrzędnego. Spróbuj usunąć z wiersza podrzędnego przed usunięciem z wiersza nadrzędnego.


To prawda, że ​​zawsze istnieje kompromis.
— Pacerier

21
Nikt nie mówi, aby tak to zawsze działać. Wyłączasz ograniczenia, ładujesz zbiorczo niektóre dane i włączasz z powrotem. Nic wielkiego, ludzie robią to cały czas.
— bwawok

jest to konieczne w przypadku importu hurtowego, przynajmniej w celu zapewnienia wydajności jest bardzo powszechne. Czasami potrzebujesz tylko przywrócić dane, a następnie możesz sprawdzić.
— Firas Abd Alrahman

3
To nie jest odpowiedź na pytanie.
— Koray Tugay,

Uwaga, jego pytanie brzmi: jak to zrobić tymczasowo. Jest to wymagane podczas wykonywania niektórych czynności konserwacyjnych i importowania danych. Zastrzeżeniem jest oczywiście to, że skrypty importu stają się odpowiedzialne za integralność danych. Następnie, gdy indeksy i ograniczenia zostaną ponownie włączone, db poinformuje cię, czy coś jest zepsute.
— mcstar
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.