Bagaimana cara menonaktifkan sementara batasan kunci asing di MySQL?


651

Apakah mungkin untuk menonaktifkan sementara kendala di MySQL?

Saya memiliki dua model Django, masing-masing dengan ForeignKey yang lain. Menghapus instance dari model akan mengembalikan kesalahan karena batasan 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()

Apakah mungkin untuk menonaktifkan sementara kendala dan menghapus pula?


3
Entah saya tidak mendapatkan apa yang ingin Anda lakukan, atau apa yang Anda coba lakukan adalah sangat, sangat, sangat jelek . Bahkan jika Anda bisa melakukannya, Anda mungkin tidak boleh melakukannya.
Dariusz

3
Menjatuhkan dan mengoleskan FK adalah mengubah db Anda. Anda mencoba untuk menentang batasan yang memungkinkan sistem untuk melihat beberapa pengertian, itu tidak menganggap bahwa FK bisa menjadi hal sementara, dan jika memang tahu, itu akan panik.
Berikan Thomas

1
Aneh apa yang Anda coba lakukan. Tetapi basis data apa yang Anda gunakan?
andrefsp

4
bagaimana jika, alih-alih menonaktifkan kendala Anda, Anda mengubahnya secara permanen ON DELETE SET NULL? Itu akan mencapai hal yang serupa dan Anda tidak perlu menghidupkan dan mematikan kunci.
dnagirl

1
@ Dnagirl: memang akan lebih baik. Bagaimana saya bisa melakukan itu?
jul

Jawaban:


1466

Coba DISABLE KEYSatau

SET FOREIGN_KEY_CHECKS=0;

pastikan untuk

SET FOREIGN_KEY_CHECKS=1;

setelah.


14
apakah ini sesuatu yang diatur untuk mysql secara keseluruhan atau hanya sesi itu?
tipu

28
Saya percaya ini per sesi.
Andrew Campbell

13
serverfault.com/questions/291100/… , Juga perhatikan bahwa Anda tidak bisa disable keys untuk Innodb
Pacerier

1
Bisakah saya menonaktifkan FOREIGN_KEY_CHECKS untuk satu tabel?
jDub9

@ Paser Dari membaca itu, tampaknya Anda bisa, tetapi hanya untuk satu sesi.
Brett

150

Untuk mematikan batasan kunci asing secara global, lakukan hal berikut:

SET GLOBAL FOREIGN_KEY_CHECKS=0;

dan ingat untuk mengaturnya kembali ketika Anda selesai

SET GLOBAL FOREIGN_KEY_CHECKS=1;

PERINGATAN: Anda hanya harus melakukan ini ketika Anda melakukan pemeliharaan mode satu pengguna. Karena mungkin mengakibatkan inkonsistensi data. Sebagai contoh, akan sangat membantu ketika Anda mengunggah sejumlah besar data menggunakan output mysqldump.


1
ini adalah apa yang perlu saya ketahui, jadi ini bukan latihan yang bagus, tetapi jawaban orang-orang ini harus mencetak lebih tinggi ...
ftrotter

1
Ini bekerja untuk saya setelah mencoba 'jawaban terbaik' tidak berhasil untuk saya. Mungkin penjelasan tentang perbedaan dapat ditambahkan.
hexnet

7
@hexnet Perbedaannya adalah bahwa baru SET FOREIGN_KEY_CHECKSsaja mengubah nilai untuk koneksi saat ini , sementara SET GLOBAL ..mengubah nilai untuk semua koneksi , termasuk koneksi di masa depan. Jika Anda hanya melakukannya SET FOREIGN..di satu jendela, kemudian mencoba menerapkan pernyataan di jendela yang berbeda (melalui koneksi yang berbeda), nilainya tidak berubah di sana. Dengan GLOBAL, variabel yang sama memiliki nilai yang sama untuk kedua koneksi.
MatsLindh

Satu-satunya hal yang bisa membantu saya ketika memainkan dump yang lebih besar (6+ GB) <3
Max

Ini tidak berhasil untuk saya. Ketika saya mencoba, saya melihat:ERROR 1228 (HY000): Variable 'foreign_key_checks' is a SESSION variable and can't be used with SET GLOBAL
Mike B

53

Saya biasanya hanya menonaktifkan batasan kunci asing ketika saya ingin memotong tabel, dan karena saya terus kembali ke jawaban ini, ini untuk saya di masa depan:

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

25

Alih-alih menonaktifkan kendala Anda, ubah secara permanen ke ON DELETE SET NULL. Itu akan mencapai hal yang serupa dan Anda tidak perlu menghidupkan dan mematikan kunci. Seperti itu:

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

Baca ini ( http://dev.mysql.com/doc/refman/5.5/en/alter-table.html ) dan ini ( http://dev.mysql.com/doc/refman/5.5/en /create-table-foreign-keys.html ).


7
Berhati-hatilah mengubah tabel bisa memakan waktu lama, lebih baik mengatur server global FOREIGN_KEY_CHECKSke 0 dan mengembalikannya setelah pekerjaan kotor selesai. Selain itu mungkin mengunci untuk menulis tabel Anda.
Aki

Bukankah itu akan mematahkan referensi ketika mengubah jenis kolom jarak jauh? (Tampaknya klien saya mengganti nama tabel temp yang dimodifikasi dengan nama tabel aslinya.)
Cees Timmerman

15

Untuk mematikan batasan kunci asing secara global:

SET GLOBAL FOREIGN_KEY_CHECKS = 0;

dan untuk batasan kunci asing aktif

SET GLOBAL FOREIGN_KEY_CHECKS = 1;

10

Solusi yang sangat sederhana dengan phpmyadmin:

  • Di meja Anda, buka SQL tab
  • Setelah Anda mengedit perintah SQL yang ingin Anda jalankan, ada kotak centang di sebelahnya GO, bernama ' Aktifkan pemeriksaan kunci asing' .
  • Hapus centang kotak ini dan jalankan SQL Anda . Ini akan secara otomatis diperiksa ulang setelah dieksekusi.

3
Terima kasih! Memang solusi SET FOREIGN_KEY_CHECKS=0; ..... SET FOREIGN_KEY_CHECKS=1;tidak berfungsi untuk saya di PHPMyAdmin karena saya lupa menghapus centang pada kotak centang 'Aktifkan pemeriksaan kunci asing'. Di PHPMyAdmin Anda dapat melewati perintah SET ini dan hapus centang pada kotak centang.
Jan

5

Bagi saya SET FOREIGN_KEY_CHECKS=0;itu tidak cukup. Saya masih memiliki com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException.

Saya harus menambahkan ALTER TABLE myTable DISABLE KEYS;.

Begitu:

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

FYI, mySQL 5.7 melempar peringatan, mesin InnoDB tidak memiliki opsi ini ketika menjalankan perintah DISABLE KEYS.
jDub9

ini berhasil, tanpa tabel perubahan juga tidak berfungsi untuk saya
David Kabii

3

Jika bidang kunci nullable, maka Anda juga dapat mengatur nilai menjadi nol sebelum mencoba menghapusnya:

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

Di phpMyAdmin Anda dapat memilih beberapa baris lalu klik tindakan hapus. Anda akan memasuki layar yang mencantumkan permintaan penghapusan, Anda dapat menghapus centang pada pemeriksaan kunci Asing, dan klik Ya untuk menjalankannya.

Ini akan memungkinkan Anda untuk menghapus baris bahkan jika ada batasan pembatasan ON DELETE.


-2

Ini bukan ide yang baik untuk menetapkan batasan kunci asing ke 0, karena jika Anda melakukannya, database Anda tidak akan memastikan itu tidak melanggar integritas referensial. Ini dapat menyebabkan data tidak akurat, menyesatkan, atau tidak lengkap.

Anda membuat kunci asing karena suatu alasan: karena semua nilai dalam kolom anak harus sama dengan nilai di kolom induk. Jika tidak ada batasan kunci asing, baris anak dapat memiliki nilai yang tidak ada di baris induk, yang akan menyebabkan data tidak akurat.

Misalnya, katakanlah Anda memiliki situs web untuk siswa masuk dan setiap siswa harus mendaftar untuk akun sebagai pengguna. Anda memiliki satu tabel untuk id pengguna, dengan id pengguna sebagai kunci utama; dan tabel lain untuk akun siswa, dengan id siswa sebagai kolom. Karena setiap siswa harus memiliki id pengguna, masuk akal untuk membuat id siswa dari tabel akun siswa kunci asing yang merujuk id pengguna kunci utama di tabel id pengguna. Jika tidak ada pemeriksaan kunci asing, siswa dapat memiliki ID siswa dan ID pengguna, yang berarti siswa dapat memperoleh akun tanpa menjadi pengguna, yang salah.

Bayangkan jika itu terjadi pada sejumlah besar data. Itu sebabnya Anda memerlukan pemeriksaan kunci asing.

Yang terbaik adalah mencari tahu apa yang menyebabkan kesalahan. Kemungkinan besar, Anda mencoba untuk menghapus dari baris induk tanpa menghapus dari baris anak. Coba hapus dari baris anak sebelum menghapus dari baris induk.


Benar, selalu ada trade-off.
Pacerier

21
Tidak ada yang mengatakan untuk menjalankannya seperti ini selamanya. Anda mematikan kendala, memuat sebagian data, dan mengaktifkannya kembali. Bukan masalah besar, orang melakukannya sepanjang waktu.
bwawok

perlu untuk impor massal, untuk kinerja setidaknya, sangat umum. juga terkadang Anda hanya perlu data untuk dipulihkan, maka Anda dapat melakukan pemeriksaan.
Firas Abd Alrahman

3
Ini bukan jawaban untuk pertanyaan itu.
Koray Tugay

Perhatikan, pertanyaannya adalah bagaimana melakukan ini sementara. Ini diperlukan saat melakukan pemeliharaan dan impor data tertentu. Peringatan tentu saja adalah bahwa skrip impor Anda menjadi bertanggung jawab atas integritas data. Kemudian, nanti ketika indeks dan batasan dihidupkan kembali, db akan memberi tahu Anda jika ada yang rusak.
mcstar
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.