ความแตกต่างระหว่าง On Delete Cascade และ On Cascade Update ใน mysql


45

ฉันมีสองตารางใน MySQL database- ,parent childฉันกำลังพยายามเพิ่มการอ้างอิงคีย์ต่างประเทศในตารางลูกของฉันตามตารางหลัก มีความแตกต่างที่สำคัญระหว่างON UPDATE CASCADEและON DELETE CASCADE

ตารางผู้ปกครองของฉัน

CREATE TABLE parent (
    id INT NOT NULL,
    PRIMARY KEY (id)
) ENGINE=INNODB;

คำถามของฉันคืออะไรความแตกต่างระหว่างการค้นหา sql ต่อไปนี้คืออะไร

  1. ON DELETE CASCADE

    CREATE TABLE child (
        id INT, 
        parent_id INT,
        INDEX par_ind (parent_id),
        FOREIGN KEY (parent_id) 
            REFERENCES parent(id)
            ON DELETE CASCADE
    ) ENGINE=INNODB;
  2. ON UPDATE CASCADE

    CREATE TABLE child (
        id INT, 
        parent_id INT,
        INDEX par_ind (parent_id),
        FOREIGN KEY (parent_id) 
            REFERENCES parent(id)
            ON UPDATE CASCADE
    ) ENGINE=INNODB;
  3. ON UPDATE CASCADE ON DELETE CASCADE

    CREATE TABLE child (
            id INT, 
            parent_id INT,
            INDEX par_ind (parent_id),
            FOREIGN KEY (parent_id) 
                REFERENCES parent(id)
                ON UPDATE CASCADE ON DELETE CASCADE
        ) ENGINE=INNODB;

มีข้อผิดพลาดในแบบสอบถามหรือไม่ ข้อความค้นหาเหล่านี้ (1,2 & 3) หมายถึงอะไร? พวกเขาเหมือนกัน ???


1
ps <nitpick> เพื่อความสมบูรณ์สิ่งที่คุณกำลังพูดถึงข้างต้นคือคำสั่ง DDL (Data Definition Language) ไม่ใช่คำสั่ง โดยทั่วไปแบบสอบถามจะถือว่าเป็น DML (Data Manipulation Language SELECT, INSERT, UPDATE, DELETE) </nitpick>
Vérace

ps อีกครั้งเพื่อความสมบูรณ์ฉันสงสัยว่าค่าเริ่มต้นคืออะไร ดังนั้นฉันจึงสร้างเด็กโดยไม่มีการอัปเดตหรือลบ สิ่งที่เกิดขึ้นคือคุณไม่สามารถอัปเดตหรือลบพาเรนต์ที่มีลูกรองได้ ที่ทำให้รู้สึกดี แต่ MySQL ไม่ได้เสมอรูปแบบของลักษณะเฉพาะที่ :-)
Vérace

คำตอบ:


64

หัวข้อที่ดีมากในเรื่องนี้จะอยู่ที่นี่และที่นี่ด้วย คู่มือการแตกหักสำหรับ MySQL เป็นของหลักสูตรเอกสารที่จะพบได้ที่นี่

ในมาตรฐาน SQL 2003 มีการดำเนินการอ้างอิงที่แตกต่างกัน 5 รายการ:

  1. น้ำตก
  2. จำกัด
  3. ไม่มีการตอบสนอง
  4. ตั้งค่าเป็นศูนย์
  5. ตั้งค่าเริ่มต้น

ในการตอบคำถาม:

  1. น้ำตก

    • ON DELETE CASCADEหมายความว่าหากบันทึกผู้ปกครองถูกลบบันทึกลูกใด ๆ จะถูกลบด้วย นี่ไม่ใช่ความคิดที่ดีในความคิดของฉัน คุณควรติดตามข้อมูลทั้งหมดที่เคยอยู่ในฐานข้อมูลแม้ว่าจะสามารถทำได้โดยใช้TRIGGERs (อย่างไรก็ตามดูข้อแม้ในความคิดเห็นด้านล่าง)

    • ON UPDATE CASCADEหมายความว่าหากคีย์หลักของผู้ปกครองเปลี่ยนไปค่าลูกจะเปลี่ยนไปตามนั้น อีกครั้งในความคิดของฉันไม่ใช่ความคิดที่ดี หากคุณกำลังเปลี่ยนPRIMARY KEYเป็นประจำ (หรือแม้แต่น้อย!) มีบางอย่างผิดปกติกับการออกแบบของคุณ ดูความคิดเห็นอีกครั้ง

    • ON UPDATE CASCADE ON DELETE CASCADEหมายความว่าถ้าคุณUPDATE หรือ DELETEผู้ปกครองการเปลี่ยนแปลงจะเรียงซ้อนกับลูก นี่คือANDผลลัพธ์ที่เทียบเท่ากับข้อความสองข้อความแรก

  2. จำกัด

    • RESTRICTหมายความว่าการพยายามลบและ / หรืออัปเดตผู้ปกครองจะล้มเหลวในการส่งข้อผิดพลาด นี่คือพฤติกรรมเริ่มต้นในกรณีที่การกระทำอ้างอิงไม่ได้ระบุไว้อย่างชัดเจน

      สำหรับON DELETEหรือON UPDATEที่ไม่ได้ระบุการกระทำเริ่มต้นจะเป็นข้อ จำกัด เสมอ

  3. ไม่มีการตอบสนอง

    • NO ACTION: จากคู่มือ คำสำคัญจาก SQL มาตรฐาน ใน MySQL, RESTRICTเทียบเท่า เซิร์ฟเวอร์ MySQL ปฏิเสธการดำเนินการลบหรืออัปเดตสำหรับตารางหลักหากมีค่าคีย์ต่างประเทศที่เกี่ยวข้องในตารางอ้างอิง ระบบฐานข้อมูลบางระบบมีการตรวจสอบที่เลื่อนออกไปและNO ACTIONเป็นการตรวจสอบที่เลื่อน ใน MySQL, ข้อ จำกัด ที่สำคัญต่างประเทศมีการตรวจสอบทันทีดังนั้นจึงเป็นเช่นเดียวกับNO ACTIONRESTRICT
  4. ตั้งค่าเป็นศูนย์

    • SET NULL- อีกครั้งจากคู่มือ ลบหรืออัพเดตแถวจากตารางพาเรนต์และตั้งค่าคอลัมน์หรือคอลัมน์คีย์ต่างประเทศในตารางNULLย่อยเป็น นี่ไม่ใช่แนวคิดที่ดีที่สุด IMHO ส่วนใหญ่เป็นเพราะไม่มี "การเดินทางข้ามเวลา" - คือการมองกลับไปที่ตารางย่อยและเชื่อมโยงระเบียนกับNULLs กับระเบียนหลักที่เกี่ยวข้อง - CASCADEหรือใช้TRIGGERs เพื่อเติมตารางการบันทึกเพื่อติดตาม การเปลี่ยนแปลง (แต่เห็นความคิดเห็น)
  5. ตั้งค่าเริ่มต้น

    • SET DEFAULT. อีกส่วนหนึ่ง (อาจมีประโยชน์มาก) เป็นส่วนหนึ่งของมาตรฐาน SQL ที่ MySQL ไม่ใส่ใจในการนำไปใช้! อนุญาตให้นักพัฒนาซอฟต์แวร์ระบุค่าที่จะตั้งค่าคอลัมน์คีย์ต่างประเทศเป็น UPDATE หรือ DELETE InnoDB และ NDB จะปฏิเสธคำจำกัดความของตารางด้วยส่วนSET DEFAULTคำสั่ง

ดังกล่าวข้างต้นที่คุณควรใช้เวลาดูที่เอกสารที่นี่


8
ฉันชอบคำตอบที่สมบูรณ์ของคุณ แต่ฉันไม่เห็นด้วยกับคำสั่งนี้ "คุณควรติดตามข้อมูลทั้งหมดที่เคยอยู่ในฐานข้อมูล" - ขึ้นอยู่กับการออกแบบและวัตถุประสงค์ของฐานข้อมูล ตัวอย่างเช่นนิยามสูตรอาหาร (ฉันไม่ได้พูดถึงอาหาร - เหมือนการกำหนดค่าระบบ) เมื่อคำจำกัดความสูตรถูกลบไปแล้วมันไม่มีเหตุผลที่จะเก็บลูก ๆ ที่เกี่ยวข้องของสูตรนั้น - นั่นก็แค่ bloats db โดยไม่มีเหตุผล นอกจากนี้ตารางการทำงานสำหรับระบบเครื่อง - ฉันไม่ต้องการข้อมูลอีกต่อไป; ดำเนินการและกำจัดทิ้ง นอกจากนั้นคำตอบของคุณนั้นวิเศษมาก
StixO

2
คล้ายกับ @StixO ฉันชอบคำตอบนี้ส่วนใหญ่ แต่ฉันไม่เห็นด้วยกับการเปลี่ยนคีย์หลัก มีการออกแบบที่แน่นอนซึ่งสิ่งนี้จะเป็นความคิดที่ไม่ดี แต่เมื่อคุณเข้าไปในฐานข้อมูลแบบกระจายมันอาจเป็นที่ต้องการอย่างมากที่คีย์หลักมีอิสระที่จะกำหนดใหม่ได้โดยไม่สูญเสียตัวตนของบันทึก
Garet Claborn

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

ตรรกะที่นี่ค่อนข้างผิดพลาดในสถานที่และยิ่งกว่านั้นในโลก GDPR ใหม่ของเรา ฉันเห็นด้วยกับความคิดที่ว่าหากคีย์หลักกำลังเปลี่ยนแปลงอาจเป็นสัญญาณว่ามีบางอย่างผิดปกติ
Chuck Le Butt

หากคุณเปลี่ยนคีย์หลักด้วยความสม่ำเสมอ (หรือแม้แต่น้อย!) แสดงว่ามีบางอย่างผิดปกติกับการออกแบบของคุณ คุณหมายถึง ON UPDATE CASCADE เปลี่ยนค่าของคีย์หรือชื่อของคีย์หรือไม่?
Billal Begueradj

8

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

หากคุณดำเนินการ:

UPDATE parent SET id = -1 WHERE id = 1;

และมีอย่างน้อยหนึ่งบันทึกchildด้วยparent_id = 1, 1) จะล้มเหลว; ในกรณีที่ 2) และ 3) ระเบียนทั้งหมดที่มี parent_id = 1 จะได้รับการอัปเดตเป็น parent_id = -1

หากคุณดำเนินการ:

DELETE FROM parent WHERE id = 1;

และมีอย่างน้อยหนึ่งบันทึกchildด้วยparent_id = 1, 2) จะล้มเหลว; ในกรณีที่ 1) และ 3) บันทึกทั้งหมดที่มีparent_id = 1จะถูกลบ

3) ถูกต้องตามหลักไวยากรณ์

เอกสารฉบับเต็มสามารถพบได้ในคู่มือการใช้งาน


6

ฉันไม่มีชื่อเสียงพอที่จะแสดงความคิดเห็นกับคำตอบก่อนหน้า ดังนั้นฉันคิดว่าฉันจะอธิบายรายละเอียดเล็กน้อย

1) ON DELETE CASCADE หมายถึงถ้าลบเร็กคอร์ดพาเรนต์ดังนั้นเร็กคอร์ดลูกที่อ้างอิงใด ๆ จะถูกลบเช่นกัน ON UPDATE จะใช้ค่าเริ่มต้นเป็น RESTRICT ซึ่งหมายความว่า UPDATE ในเรคคอร์ดหลักจะล้มเหลว

2) ON DELETE การกระทำเริ่มต้นเพื่อ RESTRICT ซึ่งหมายความว่าการลบในบันทึกผู้ปกครองจะล้มเหลว ON CASCADE UPDATE จะอัปเดตบันทึกลูกอ้างอิงทั้งหมดเมื่อมีการปรับปรุงระเบียนแม่

3) ดูการกระทำแบบเรียงซ้อนใน 1) และ 2) ด้านบน

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

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