วิธีการปิดการใช้งานข้อ จำกัด กุญแจต่างประเทศชั่วคราวใน MySQL?


651

เป็นไปได้หรือไม่ที่จะปิดการใช้งานข้อ จำกัด ใน MySQL ชั่วคราว?

ฉันมี Django สองรุ่นโดยแต่ละรุ่นมี ForeignKey อยู่หนึ่งรุ่น การลบอินสแตนซ์ของโมเดลส่งคืนข้อผิดพลาดเนื่องจากข้อ จำกัด 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()

เป็นไปได้หรือไม่ที่จะปิดการใช้งานข้อ จำกัด ชั่วคราวและลบต่อไป?


3
ไม่ว่าฉันจะไม่ได้สิ่งที่คุณต้องการหรือสิ่งที่คุณพยายามทำนั้นน่ากลัวมากๆ แม้ว่าคุณสามารถทำได้คุณอาจไม่ควรทำ
Dariusz

3
การดร็อปและการใช้ FK อีกครั้งกำลังเปลี่ยน db ของคุณ คุณกำลังพยายามท้าทายข้อ จำกัด ที่ทำให้ระบบมองเห็นบางอย่างไม่ว่า FK อาจเป็นสิ่งชั่วคราวและถ้ามันรู้ก็จะตกใจ
โทมัส

1
มันแปลกในสิ่งที่คุณพยายามจะทำ แต่คุณใช้ฐานข้อมูลใดอยู่
andrefsp

4
สิ่งที่ถ้าแทนการปิดการใช้งานข้อ จำกัด ของคุณคุณการแก้ไขอย่างถาวรมันON DELETE SET NULL? นั่นจะทำให้สิ่งเดียวกันสำเร็จและคุณไม่ต้องเปิดและปิดการตรวจสอบคีย์
dnagirl

1
@dnagirl: นั่นจะดีกว่าแน่นอน ฉันจะทำสิ่งนั้นได้อย่างไร
กรกฎาคม

คำตอบ:


1466

ลองDISABLE KEYSหรือ

SET FOREIGN_KEY_CHECKS=0;

ทำให้แน่ใจว่า

SET FOREIGN_KEY_CHECKS=1;

หลังจาก.


14
เป็นสิ่งที่กำหนดไว้สำหรับ mysql ทั้งหมดหรือเพียงแค่เซสชั่นที่?
tipu

28
ฉันเชื่อว่ามันเป็นต่อเซสชั่น
แอนดรูแคมป์เบล

13
serverfault.com/questions/291100/…โปรดทราบว่าคุณไม่สามารถ disable keysใช้ Innodb
Pacerier ได้

1
ฉันสามารถปิดการใช้งาน FOREIGN_KEY_CHECKS สำหรับตารางเดียวได้ไหม
jDub9

@Pacerier จากการอ่านที่ปรากฏคุณสามารถทำได้ แต่เพียงครั้งเดียวเท่านั้น
Brett

150

หากต้องการปิดข้อ จำกัด foreign key ทั่วโลกให้ทำดังต่อไปนี้:

SET GLOBAL FOREIGN_KEY_CHECKS=0;

และอย่าลืมตั้งค่าเมื่อคุณทำเสร็จแล้ว

SET GLOBAL FOREIGN_KEY_CHECKS=1;

คำเตือน: คุณควรทำเช่นนี้เฉพาะเมื่อคุณทำการบำรุงรักษาโหมดผู้ใช้คนเดียว เนื่องจากอาจทำให้ข้อมูลไม่สอดคล้องกัน ตัวอย่างเช่นจะมีประโยชน์มากเมื่อคุณอัปโหลดข้อมูลจำนวนมากโดยใช้เอาต์พุต mysqldump


1
นี้คือสิ่งที่ฉันจำเป็นต้องรู้เพื่อการปฏิบัติที่ไม่ดี แต่คำตอบที่คนควรจะได้รับคะแนนสูงกว่า ...
ftrotter

1
สิ่งนี้ใช้ได้กับฉันหลังจากลอง 'คำตอบที่ดีที่สุด' ไม่ได้ผลสำหรับฉัน บางทีคำอธิบายของความแตกต่างอาจถูกเพิ่มเข้าไป
hexnet

7
@hexnet ความแตกต่างคือเพียงSET FOREIGN_KEY_CHECKSแค่เปลี่ยนค่าสำหรับการเชื่อมต่อปัจจุบันในขณะที่SET GLOBAL ..เปลี่ยนค่าสำหรับการเชื่อมต่อทั้งหมดรวมถึงการเชื่อมต่อในอนาคต หากคุณทำSET FOREIGN..ในหน้าต่างเดียวให้ลองใช้คำสั่งในหน้าต่างอื่น (ผ่านการเชื่อมต่ออื่น) ค่าจะไม่เปลี่ยนไป ด้วยGLOBALตัวแปรเดียวกันมีค่าเท่ากันสำหรับการเชื่อมต่อทั้งสอง
MatsLindh

สิ่งเดียวที่สามารถช่วยฉันได้เมื่อเล่นการถ่ายโอนข้อมูลที่มีขนาดใหญ่ขึ้น (6+ GB) <3
สูงสุด

มันไม่ได้ผลสำหรับฉัน เมื่อฉันลองฉันจะเห็น:ERROR 1228 (HY000): Variable 'foreign_key_checks' is a SESSION variable and can't be used with SET GLOBAL
Mike B

53

ปกติฉันจะปิดการใช้งานข้อ จำกัด กุญแจต่างประเทศเฉพาะเมื่อฉันต้องการตัดทอนตารางและเนื่องจากฉันกลับมาที่คำตอบนี้นี่คือสำหรับฉันในอนาคต:

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

25

แทนที่จะปิดใช้งานข้อ จำกัด ของคุณให้แก้ไขอย่างถาวรเป็น ON DELETE SET NULL นั่นจะทำให้สิ่งที่คล้ายกันสำเร็จและคุณไม่ต้องเปิดและปิดการตรวจสอบคีย์ ชอบมาก

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

อ่านเรื่องนี้ ( http://dev.mysql.com/doc/refman/5.5/en/alter-table.html ) และสิ่งนี้ ( http://dev.mysql.com/doc/refman/5.5/en /create-table-foreign-keys.html )


7
ระวังการเปลี่ยนแปลงตารางอาจใช้เวลานานดีกว่าที่จะตั้งค่าเซิร์ฟเวอร์ทั่วโลกFOREIGN_KEY_CHECKSเป็น 0 และนำกลับมาใช้เมื่องานสกปรกเสร็จสิ้น นอกจากนี้มันอาจล็อคการเขียนตารางของคุณ
Aki

จะไม่ทำลายการอ้างอิงเมื่อแก้ไขประเภทคอลัมน์ระยะไกลหรือไม่ (ดูเหมือนว่าลูกค้าของฉันเปลี่ยนชื่อตารางชั่วคราวแก้ไขเพื่อให้ชื่อตารางเดิม.)
Cees Timmerman

15

หากต้องการปิดการ จำกัด คีย์ต่างประเทศทั่วโลก:

SET GLOBAL FOREIGN_KEY_CHECKS = 0;

และสำหรับข้อ จำกัด ที่สำคัญต่างประเทศที่ใช้งาน

SET GLOBAL FOREIGN_KEY_CHECKS = 1;

10

ทางออกที่ง่ายมากกับ phpmyadmin:

  • ในตารางของคุณไปที่SQLแท็บ
  • หลังจากที่คุณแก้ไขคำสั่ง SQL ที่คุณต้องการเรียกใช้มีกล่องกาเครื่องหมายที่อยู่ถัดจากGOชื่อ ' เปิดใช้งานการตรวจสอบที่สำคัญต่างประเทศ'
  • ยกเลิกการเลือกช่องทำเครื่องหมายนี้และเรียกใช้ SQL มันจะถูกตรวจสอบอีกครั้งโดยอัตโนมัติหลังจากดำเนินการ

3
ขอบคุณ! ทางออกที่แท้จริงSET FOREIGN_KEY_CHECKS=0; ..... SET FOREIGN_KEY_CHECKS=1;ไม่ได้ผลสำหรับฉันใน PHPMyAdmin เพราะฉันลืมที่จะยกเลิกการเลือกช่องทำเครื่องหมาย 'เปิดใช้งานการตรวจสอบคีย์ต่างประเทศ' ใน PHPMyAdmin คุณสามารถข้ามคำสั่ง SET เหล่านี้และเพียงยกเลิกการเลือกที่ช่องทำเครื่องหมาย
Jan

5

สำหรับฉันแค่SET FOREIGN_KEY_CHECKS=0;ไม่เพียงพอ com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationExceptionฉันก็ยังคงมี

ALTER TABLE myTable DISABLE KEYS;ผมต้องเพิ่ม

ดังนั้น:

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 แจ้งเตือน, เครื่องยนต์ InnoDB ไม่มีตัวเลือกนี้เมื่อใช้คำสั่ง DISABLE KEYS
jDub9

สิ่งนี้ใช้ได้ผลหากไม่มีตารางเปลี่ยนแปลงมันก็ไม่ได้ผลสำหรับฉัน
เดวิดคาบี

3

หากฟิลด์คีย์เป็นโมฆะคุณสามารถตั้งค่าเป็นโมฆะก่อนที่จะพยายามลบ:

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 คุณสามารถเลือกหลายแถวแล้วคลิกการกระทำลบ คุณจะเข้าสู่หน้าจอที่แสดงคำสั่งการลบคุณสามารถยกเลิกการเลือกตรวจสอบคีย์ต่างประเทศและคลิกที่ใช่เพื่อดำเนินการ

สิ่งนี้จะช่วยให้คุณสามารถลบแถวได้แม้ว่าจะมีข้อ จำกัด ON DELETE


-2

ไม่ใช่ความคิดที่ดีที่จะตั้งข้อ จำกัด foreign key เป็น 0 เพราะถ้าคุณทำเช่นนั้นฐานข้อมูลของคุณจะไม่ตรวจสอบให้แน่ใจว่ามันไม่ได้ละเมิด Referential Integrity ซึ่งอาจนำไปสู่ข้อมูลที่ไม่ถูกต้องทำให้เข้าใจผิดหรือข้อมูลที่ไม่สมบูรณ์

คุณสร้าง foreign key ด้วยเหตุผล: เนื่องจากค่าทั้งหมดในคอลัมน์ชายน์จะต้องเหมือนกับค่าในคอลัมน์ parent หากไม่มีข้อ จำกัด กุญแจต่างประเทศแถวลูกสามารถมีค่าที่ไม่ได้อยู่ในแถวหลักซึ่งจะนำไปสู่ข้อมูลที่ไม่ถูกต้อง

ตัวอย่างเช่นสมมติว่าคุณมีเว็บไซต์สำหรับนักเรียนที่จะเข้าสู่ระบบและนักเรียนทุกคนจะต้องลงทะเบียนสำหรับบัญชีในฐานะผู้ใช้ คุณมีหนึ่งตารางสำหรับ ID ผู้ใช้โดยมี ID ผู้ใช้เป็นคีย์หลัก และอีกตารางสำหรับบัญชีนักเรียนโดยมีรหัสนักศึกษาเป็นคอลัมน์ เนื่องจากนักเรียนทุกคนต้องมี ID ผู้ใช้จึงเป็นเรื่องเหมาะสมที่จะทำให้รหัสนักศึกษาจากตารางบัญชีนักเรียนเป็นรหัสต่างประเทศที่อ้างอิงถึงรหัสผู้ใช้รหัสหลักในตารางรหัสผู้ใช้ หากไม่มีการตรวจสอบกุญแจต่างประเทศนักเรียนอาจพบว่ามีรหัสนักศึกษาและไม่มีรหัสผู้ใช้ซึ่งหมายความว่านักเรียนจะได้รับบัญชีโดยไม่ต้องเป็นผู้ใช้ซึ่งผิด

ลองนึกภาพถ้ามันเกิดขึ้นกับข้อมูลจำนวนมาก นั่นเป็นเหตุผลที่คุณต้องตรวจสอบกุญแจต่างประเทศ

เป็นการดีที่สุดที่จะทราบว่าอะไรเป็นสาเหตุของข้อผิดพลาด เป็นไปได้มากว่าคุณกำลังพยายามลบจากแถวหลักโดยไม่ต้องลบออกจากแถวลูก ลองลบจากแถวลูกก่อนที่จะลบออกจากแถวหลัก


จริงมีการแลกเปลี่ยนอยู่เสมอ
Pacerier

21
ไม่มีใครพูดว่าให้ทำอย่างนี้ตลอดไป คุณปิดข้อ จำกัด โหลดข้อมูลจำนวนมากแล้วเปิดอีกครั้ง ไม่มีเรื่องใหญ่คนทำตลอดเวลา
bwawok

มันเป็นสิ่งจำเป็นสำหรับการนำเข้าจำนวนมากสำหรับประสิทธิภาพอย่างน้อยก็เป็นเรื่องธรรมดามาก บางครั้งคุณเพียงแค่ต้องการกู้คืนข้อมูลจากนั้นคุณสามารถทำการตรวจสอบของคุณ
Firas Abd Alrahman

3
นี่ไม่ใช่คำตอบสำหรับคำถาม
Koray Tugay

หมายเหตุคำถามของเขาคือทำอย่างไรชั่วคราว สิ่งนี้จำเป็นเมื่อทำการบำรุงรักษาและนำเข้าข้อมูล คำเตือนของหลักสูตรคือสคริปต์นำเข้าของคุณรับผิดชอบความถูกต้องของข้อมูล จากนั้นในภายหลังเมื่อดัชนีและข้อ จำกัด ถูกเปิดใช้งานใหม่ฐานข้อมูลจะแจ้งให้คุณทราบหากมีสิ่งใดเสียหาย
mcstar
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.