MySQL'de yabancı anahtar kısıtlamasını geçici olarak nasıl devre dışı bırakabilirim?


651

MySQL'de kısıtlamaları geçici olarak devre dışı bırakmak mümkün mü?

İki Django modelim var, her biri diğerine ForeignKey. Bir modelin örneklerini silmek, ForeignKey kısıtlaması nedeniyle bir hata döndürür:

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

Kısıtlamaları geçici olarak devre dışı bırakmak ve yine de silmek mümkün müdür?


3
Ya ne yapmak istediğini anlamıyorum ya da yapmaya çalıştığın şey çok, çok, çok çirkin . Yapabilseniz bile, muhtemelen yapmamalısınız.
Dariusz

3
Damlama ve FK yeniden uygulanması olduğunu da db değiştirerek. Sistemin bir anlam görmesine izin veren kısıtlamalara karşı koymaya çalışıyorsunuz, bir FK'nin geçici bir şey olabileceği konusunda hiçbir önemi yok ve eğer bilseydi panikleyecektir.
Grant

1
Yapmaya çalıştığın garip. Ama hangi veritabanını kullanıyorsunuz?
andrefsp

4
kısıtlamalarınızı devre dışı bırakmak yerine kalıcı olarak değiştirirseniz ne olur ON DELETE SET NULL? Bu benzer bir şey başaracak ve anahtar kontrolünü açıp kapatmak zorunda kalmayacaksınız.
dnagirl 19:13

1
@dnagirl: bu gerçekten daha iyi olurdu. Bunu nasıl yapabilirim?
Temmuz

Yanıtlar:


1466

Deneyin DISABLE KEYSveya

SET FOREIGN_KEY_CHECKS=0;

emin ol

SET FOREIGN_KEY_CHECKS=1;

sonra.


14
Bu mysql için bir bütün olarak mı yoksa sadece bu oturum için mi ayarlanmış?
tipu

28
Oturum başına olduğuna inanıyorum.
Andrew Campbell


1
FOREIGN_KEY_CHECKS ürününü tek bir tablo için devre dışı bırakabilir miyim?
jDub9

@Pacerier Bunu okuduğunuzda, sadece tek bir oturum için yapabilirsiniz.
Brett

150

Yabancı anahtar kısıtlamasını global olarak kapatmak için aşağıdakileri yapın:

SET GLOBAL FOREIGN_KEY_CHECKS=0;

ve işiniz bittiğinde tekrar ayarlamayı unutmayın

SET GLOBAL FOREIGN_KEY_CHECKS=1;

UYARI: Bunu yalnızca tek kullanıcı modu bakımı yaparken yapmanız gerekir. Veri tutarsızlığı ile sonuçlanabileceğinden. Örneğin, bir mysqldump çıktısı kullanarak büyük miktarda veri yüklerken çok yardımcı olacaktır.


1
Bu bilmem gereken şey, bu yüzden büyük bir uygulama değil, ama bu adamların cevabı daha yüksek puan almalıdır ...
ftrotter

1
'En iyi cevabı' denedikten sonra benim için işe yaramadı. Belki de farkın bir açıklaması eklenebilir.
hexnet

7
@hexnet fark sadece budur SET FOREIGN_KEY_CHECKSsadece değerini değiştirir akım bağlantısı ise, SET GLOBAL ..değer değiştirir tüm bağlantıların gelecek bağlantıları gibi. Sadece SET FOREIGN..bir pencerede yaparsanız , ifadeyi farklı bir pencerede (farklı bir bağlantı üzerinden) uygulamayı deneyin, değer orada değişmez. İle GLOBAL, aynı değişken her iki bağlantı için de aynı değere sahiptir.
MatsLindh

Daha büyük bir çöplüğü (6+ GB) oynatırken bana yardımcı olabilecek tek şey <3
Max

Bu benim için işe yaramıyor. Denediğimde, şunu görüyorum:ERROR 1228 (HY000): Variable 'foreign_key_checks' is a SESSION variable and can't be used with SET GLOBAL
Mike B

53

Normalde yalnızca bir tabloyu kesmek istediğimde yabancı anahtar kısıtlamalarını devre dışı bırakıyorum ve bu cevaba geri dönmeye devam ettiğim için bu gelecekteki benim için:

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

25

Kısıtlamanızı devre dışı bırakmak yerine, kalıcı olarak ON DELETE SET NULL olarak ayarlayın. Bu benzer bir şey başaracak ve anahtar kontrolünü açıp kapatmak zorunda kalmayacaksınız. Şöyle ki:

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

Bunu ( http://dev.mysql.com/doc/refman/5.5/en/alter-table.html ) ve bunu ( http://dev.mysql.com/doc/refman/5.5/en ) okuyun /create-table-foreign-keys.html ).


7
Değiştirme tablo uzun sürebilir, sunucuyu FOREIGN_KEY_CHECKS0 için küresel ayarlamak daha iyi ve kirli iş bittiğinde geri koymak. Ayrıca tablolarınızı yazmak için kilitlenebilir.
Aki

Uzak sütun türünü değiştirirken referans kesilmez mi? (Görünüşe göre müşterim değiştirilmiş bir geçici tabloyu orijinal tablo adına yeniden adlandırıyor.)
Cees Timmerman

15

Yabancı anahtar kısıtlamasını küresel olarak kapatmak için:

SET GLOBAL FOREIGN_KEY_CHECKS = 0;

ve aktif yabancı anahtar kısıtı için

SET GLOBAL FOREIGN_KEY_CHECKS = 1;

10

Phpmyadmin ile çok basit bir çözüm:

  • Tablonuzda SQLsekmeye gidin
  • Çalıştırmak istediğiniz SQL komutunu düzenledikten sonra GO, ' Yabancı anahtar denetimlerini etkinleştir ' adlı bir onay kutusu bulunur .
  • Bu onay kutusunun işaretini kaldırın ve SQL'inizi çalıştırın . Yürütüldükten sonra otomatik olarak yeniden kontrol edilecektir.

3
Teşekkürler! Gerçekten de SET FOREIGN_KEY_CHECKS=0; ..... SET FOREIGN_KEY_CHECKS=1;PHPMyAdmin'de çözüm benim için işe yaramadı çünkü 'Yabancı anahtar kontrollerini etkinleştir' onay kutusunun işaretini kaldırmayı unuttum. PHPMyAdmin'de bu SET komutlarını atlayabilir ve onay kutusunun işaretini kaldırabilirsiniz.
Ocak

5

Benim SET FOREIGN_KEY_CHECKS=0;için yeterli değildi. Hala bir com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException.

Eklemek zorundaydım ALTER TABLE myTable DISABLE KEYS;.

Yani:

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 uyarı verir, DISno KEYS komutunu çalıştırırken InnoDB motoru bu seçeneğe sahip değildir.
jDub9

bu işe yaradı, alter tablosu olmadan da benim için çalışmadı
David Kabii

3

Anahtar alanı boşsa, silmeye çalışmadan önce değeri null olarak da ayarlayabilirsiniz:

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

PhpMyAdmin'de birden çok satır seçip silme eylemini tıklayabilirsiniz. Silme sorgularını listeleyen bir ekrana gireceksiniz, Yabancı anahtar kontrolünün işaretini kaldırabilir ve yürütmek için Evet'e tıklayabilirsiniz.

Bu, bir ON DELETE kısıtlama kısıtlaması olsa bile satırları silmenizi sağlar.


-2

Yabancı anahtar kısıtlamasını 0 olarak ayarlamak iyi bir fikir değildir, çünkü bunu yaparsanız veritabanınız referans bütünlüğünü ihlal etmediğinden emin olmaz. Bu, yanlış, yanıltıcı veya eksik verilere yol açabilir.

Bir nedenle yabancı anahtar yaparsınız: çünkü alt sütundaki tüm değerler üst sütundaki bir değerle aynı olacaktır. Yabancı anahtar kısıtlaması yoksa, bir alt satırın üst satırda olmayan ve yanlış verilere yol açacak bir değeri olabilir.

Örneğin, öğrencilerin giriş yapabileceği bir web siteniz olduğunu ve her öğrencinin bir hesap için kullanıcı olarak kaydolması gerektiğini varsayalım. Kullanıcı kimlikleri için birincil anahtar olarak kullanıcı kimliğine sahip bir tablonuz var; ve öğrenci kimliği için sütun olarak öğrenci kimliğine sahip başka bir tablo. Her öğrencinin bir kullanıcı kimliği olması gerektiğinden, öğrenci hesapları tablosundaki öğrenci kimliğini, kullanıcı kimlikleri tablosundaki birincil anahtar kullanıcı kimliğine başvuran yabancı bir anahtar yapmak mantıklı olacaktır. Yabancı anahtar kontrolü yoksa, öğrenci öğrenci kimliği ve kullanıcı kimliği içermeyebilir, bu da öğrencinin kullanıcı olmadan hesap alabileceği anlamına gelir, bu yanlıştır.

Büyük miktarda veriye gelip gelmediğini düşünün. Bu yüzden yabancı anahtar kontrolüne ihtiyacınız var.

Hataya neyin neden olduğunu bulmak en iyisidir. Büyük olasılıkla, bir alt satırdan silmeden bir üst satırdan silmeye çalışıyorsunuz. Üst satırdan silmeden önce alt satırdan silmeyi deneyin.


Doğru, her zaman bir değiş tokuş vardır.
Pacerier

21
Kimse sonsuza dek böyle çalıştırmak istemiyor. Kısıtlamaları kapatır, bazı verileri toplu olarak yükler ve tekrar açarsınız. Önemli değil, insanlar her zaman yapıyor.
bwawok

toplu ithalat için gereklidir, en azından performans için çok yaygındır. ayrıca bazen verilerin geri yüklenmesi yeterlidir, o zaman kontrollerinizi yapabilirsiniz.
Firas Abd Alrahman

3
Bu sorunun cevabı değil.
Koray Tugay

Unutmayın, sorusu bunun geçici olarak nasıl yapılacağıdır. Bu, belirli bakım ve veri aktarımlarını yaparken gereklidir. Elbette, içe aktarma komut dosyalarınızın veri bütünlüğünden sorumlu hale gelmesidir. Daha sonra, dizinler ve kısıtlamalar tekrar açıldığında, db size bir şeyin bozuk olup olmadığını söyler.
mcstar
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.