ข้อเสียของการใช้ foreign key แบบ nullable แทนการสร้างตาราง intersection


15

ว่าฉันมีแผนภาพ ER ต่อไปนี้:

ป้อนคำอธิบายรูปภาพที่นี่

ตอนนี้ถ้าฉันแสดงถึงความสัมพันธ์โดยใช้ foreign key ของSchoolin StudentฉันสามารถมีNULLค่าได้(เนื่องจาก a Student ไม่จำเป็นต้องเป็นของ a School) ตัวอย่างเช่น:

ป้อนคำอธิบายรูปภาพที่นี่

ดังนั้นวิธีที่ถูกต้อง (ขึ้นอยู่กับสิ่งที่ฉันได้อ่าน) คือการสร้างตารางสี่แยกเพื่อเป็นตัวแทนของความสัมพันธ์ตัวอย่างเช่น

ป้อนคำอธิบายรูปภาพที่นี่

วิธีนี้ไม่มีค่าสามารถจะนำเสนอในตารางNULLSchool_has_Student

แต่อะไรคือข้อเสียของการใช้ foreign key แบบ nullable แทนการสร้างตาราง intersection?


แก้ไข:

ฉันเลือก ( school_id, student_id) เป็นคีย์หลักสำหรับSchool_has_Studentตารางโดยไม่ตั้งใจซึ่งทำให้ความสัมพันธ์แบบนี้มีมากหลายต่อหลายคน คีย์หลักที่ถูกต้องควรเป็นstudent_id:

ป้อนคำอธิบายรูปภาพที่นี่


7
ไม่มีวิธี "ถูกต้อง" มีวิธีที่ดีที่สุดสำหรับความต้องการของคุณ
MetaFight

1
ฉันเห็นด้วยกับ Doc เกี่ยวกับสถานที่ตั้งผิด ๆ แต่บางทีมันอาจจะชัดเจนเพียงพอที่จะตอบ
MetaFight

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

ฉันถอนการโหวตอย่างใกล้ชิดของฉัน แต่ประโยค"ดังนั้นวิธีที่ถูกต้อง (ตามสิ่งที่ฉันได้อ่าน) คือการสร้างตารางสี่แยกเพื่อเป็นตัวแทนของความสัมพันธ์"ให้ความประทับใจแก่คุณคุณควรบอกเราว่า วิธีที่ถูกต้อง ในหนังสือทุกเล่มที่ฉันได้อ่านก่อนหน้านี้วิธีที่เป็นที่ยอมรับสำหรับความสัมพันธ์ 1: n เป็นคีย์ต่างประเทศเดียว หรือคุณเข้าใจผิดบางอย่าง?
Doc Brown

@Doc Brown ฉันจำไม่ได้ว่าอ่านแล้ว แต่ฉันแน่ใจว่ามันบอกว่าตารางแยกเป็นวิธีที่ถูกต้อง อย่างไรก็ตามคุณสามารถให้ชื่อหนังสือที่บอกว่าความสัมพันธ์ 1: n (ด้วยการมีส่วนร่วมเสริม: 1 ด้าน) ควรแสดงโดยใช้กุญแจต่างประเทศเดียวฉันสนใจที่จะอ่านสิ่งที่พวกเขาพูดเกี่ยวกับเรื่องนี้
ทอม

คำตอบ:


18

ทั้งสองรุ่นแสดงถึงความสัมพันธ์ที่แตกต่าง

โดยใช้ตารางเข้าร่วมคุณกำลังสร้างแบบจำลองความสัมพันธ์แบบหลายต่อหลายคน

ด้วยการใช้รหัสต่างประเทศแบบง่ายคุณกำลังสร้างแบบจำลองความสัมพันธ์แบบหนึ่งต่อหลายคน

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


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

ด้วยการแยกตารางนักเรียนคุณจะทำให้ตารางที่สองเป็นทางเลือกเนื่องจากระเบียนไม่จำเป็นต้องมีอยู่ในตารางที่สอง ซึ่งคล้ายกับฟิลด์ที่ไม่จำเป็นต้องตั้งค่าเนื่องจากอาจเป็นโมฆะ

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

หากคุณกังวลเกี่ยวกับการเข้าร่วมไม่ต้องกังวล มีซีแมนติกส์ที่กำหนดไว้อย่างดีสำหรับวิธีการทำงานร่วมกับเขตข้อมูล null โดยใช้ตารางเดียวคุณสามารถเข้าร่วมสองตารางแทนสาม


ดังนั้นถ้าฉันกำลังสร้างโมเดลความสัมพันธ์แบบหนึ่งต่อหลายคน (ด้วยการมีส่วนร่วมเสริมใน: 1 ด้าน) ฉันควรใช้รหัสต่างประเทศแม้ว่าจะมีNULLคุณค่าหรือไม่?
ทอม

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

1
ฉันแก้ไขคำถามของฉัน ฉันสร้างstudent_idคีย์หลักในSchool_has_Studentตารางซึ่งเก็บความสัมพันธ์แบบหนึ่งต่อหลายคนเท่านั้น วิธีนี้มีข้อเสียอะไรในการใช้คีย์ต่างประเทศ?
ทอม

@ ฉันจะแก้ไขคำตอบของฉัน

6

คุณเขียนในความคิดเห็นด้านบน:

หนังสือ "ความรู้พื้นฐานของระบบฐานข้อมูล" [... ] บอกว่า [... ] แนะนำให้ใช้ตารางจุดแยกหากมีค่า NULL จำนวนมากในคอลัมน์คีย์ต่างประเทศ (เช่น: ถ้าพนักงาน 98% ไม่ได้จัดการแผนก)

เมื่อมีค่า NULL จำนวนมากในคอลัมน์ foreign key โปรแกรมของคุณจะต้องจัดการกับคอลัมน์ที่ว่างเปล่าส่วนใหญ่นี้สำหรับแต่ละระเบียนที่ประมวลผล คอลัมน์อาจใช้พื้นที่ดิสก์บางส่วนแม้ว่าใน 98% ของทุกกรณีจะว่างเปล่าการสืบค้นความสัมพันธ์หมายถึงการสืบค้นคอลัมน์นั้นซึ่งให้ปริมาณการใช้เครือข่ายมากขึ้นและถ้าคุณใช้ ORM ซึ่งสร้างคลาสจากตารางโปรแกรมของคุณ จะต้องการพื้นที่เพิ่มเติมที่ฝั่งไคลเอ็นต์เกินความจำเป็น การใช้ตารางการตัดกันจะหลีกเลี่ยงสิ่งนี้จะมีเพียงบันทึกการเชื่อมโยงที่จำเป็นซึ่งคีย์ foreign ที่เทียบเท่าจะไม่เป็น NULL

ตรงข้ามกับที่ถ้าคุณมีค่า NULL เพียงไม่กี่ค่าให้บอกว่าความสัมพันธ์ 50% หรือมากกว่านั้นไม่ใช่ NULL การใช้ตารางการแยกจะให้ผลตรงกันข้าม - เนื้อที่ดิสก์มากขึ้นความซับซ้อนที่สูงขึ้นทำให้เครือข่ายมีปริมาณมากขึ้นเป็นต้น

ดังนั้นการใช้ตารางจุดตัดจึงเป็นเพียงการเพิ่มประสิทธิภาพเพียงอย่างเดียวสำหรับกรณีเฉพาะและโดยเฉพาะอย่างยิ่งในปัจจุบันที่พื้นที่ดิสก์และหน่วยความจำมีราคาถูกลง โปรดทราบว่าเดิมที "ความรู้พื้นฐานของระบบฐานข้อมูล" ถูกเขียนมานานกว่า 20 ปีแล้ว (ฉันพบการอ้างอิงถึงรุ่นที่สองจากปี 1994) และฉันเดาว่าคำแนะนำนั้นมีอยู่แล้วในเวลานั้น ก่อนปี 1994 การเพิ่มประสิทธิภาพของพื้นที่อาจมีความสำคัญมากกว่าวันนี้เนื่องจากพื้นที่เก็บข้อมูลขนาดใหญ่ยังมีราคาแพงกว่าและคอมพิวเตอร์และเครือข่ายช้ากว่าวันนี้มาก

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

ดังนั้นอย่าเข้าใจผิดว่า หนังสือเล่มนี้ไม่ได้บอกให้คุณชอบตารางจุดตัดสำหรับ{0,1}:nความสัมพันธ์โดยทั่วไปหรือ - ตามที่คุณเขียน - ว่านี่เป็น "วิธีที่ถูกต้อง" ใช้การปรับให้เหมาะสมเช่นนี้ซึ่งจะทำให้โปรแกรมของคุณซับซ้อนยิ่งขึ้นเมื่อคุณต้องการจริงๆเท่านั้น


คุณคาดเดามากเกี่ยวกับการใช้ฐานข้อมูลโดยเฉพาะการพิจารณา OP ไม่ได้กล่าวถึงเฉพาะ เป็นไปได้มากกว่าที่ฐานข้อมูลฉลาดพอที่จะใช้พื้นที่เพียงเล็กน้อยสำหรับคอลัมน์ที่กระจาย
Gardenhead

@gardenhead: อะไรที่ทำให้คุณเชื่อว่านี่เป็น "มากกว่า"
Doc Brown

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

@gardenhead: ฟังดูฉันว่าคุณมีข้อสันนิษฐานที่ไม่ยุติธรรมมากนักกว่าฉัน อย่างไรก็ตามดูการแก้ไขของฉัน
Doc Brown

2

แบบจำลองแนวคิดจะมีลักษณะเช่นนี้ซึ่งไม่น่าเชื่อมากนักที่จะพูดน้อย:

ป้อนคำอธิบายรูปภาพที่นี่

แบบจำลองทางกายภาพจะมีลักษณะเช่นนี้ซึ่งสร้างความสับสนในการพูดน้อย (ผู้คนจะคิดว่าเป็น M: M ยกเว้นว่าพวกเขาเห็นอย่างใกล้ชิด):

ป้อนคำอธิบายรูปภาพที่นี่

คำแนะนำของฉัน:

หากคุณต้องการคอลัมน์จำนวนมาก (FK หรืออื่น ๆ ) ที่ไม่ได้ใช้กับนักเรียนส่วนใหญ่ให้แยกตารางออกเป็นตารางบทบาทโดยใช้การถ่ายทอด 1: 1 แต่นั่นไม่ใช่เพราะมันเป็น FK มันเป็นเพราะคอลัมน์ไม่ได้ใช้กับแถวส่วนใหญ่

มิฉะนั้น , nullable FK เป็นส่วนหนึ่งของฐานข้อมูลและเข้าร่วมโต๊ะมักจะมีสำหรับ M: M rels

การใช้งานทั่วไปของ 1: 1 rels ใช้สำหรับตารางบทบาทที่มีคอลัมน์ที่ใช้เฉพาะถ้าเอนทิตีนั้นเป็นประเภทที่แน่นอนและการแยกคอลัมน์ BLOB สำหรับการพิจารณาประสิทธิภาพหรือการจัดเก็บ การเข้ารหัสค่า Null ใน FK ไม่ใช่การใช้งานทั่วไปสำหรับสิ่งนั้น

ป้อนคำอธิบายรูปภาพที่นี่


2

นอกจากคำตอบอื่น ๆ ฉันอยากจะชี้ให้เห็นว่าค่า Null สำหรับคีย์ต่างประเทศนั้นไม่ชัดเจน มันหมายความว่า:

1) ไม่ทราบโรงเรียนของนักเรียน (ถ้ามี) (นี่คือความหมายมาตรฐานของ 'null' - ไม่ทราบค่า)

2) เป็นที่รู้กันว่านักเรียนมีโรงเรียนหรือไม่และไม่มีเลย

หากคุณใช้ความหมายมาตรฐานเป็นโมฆะคุณจะเป็นตัวแทนของ "นักเรียนไม่มีโรงเรียน" ในรูปแบบกุญแจต่างประเทศของคุณอย่างไร ในกรณีนี้คุณอาจต้องสร้างรายการ "ไม่มีโรงเรียน" ด้วยรหัสของตัวเองในตารางโรงเรียน (ไม่เหมาะ)


2
หนังสือ"ความรู้พื้นฐานของระบบฐานข้อมูล"ระบุว่ามีการตีความ 3 ครั้งNULLซึ่งอาจหมายถึง: 1) ค่าที่ไม่รู้จัก 2) ค่าไม่พร้อมใช้งานหรือถูกระงับ 3) แอตทริบิวต์ที่ไม่เกี่ยวข้อง (ฉันคิดว่าการตีความนี้หมายความว่าคุณสามารถระบุNULLรหัสต่างประเทศได้)
ทอม

1
นั่นเป็นรายการที่มีประโยชน์ แต่ความหมายของ null (หรือค่าใด ๆ จริงๆ) นั้นสามารถกำหนดได้โดยผู้ใช้ คือมันอาจหมายถึงสิ่งที่นักออกแบบบอกว่ามันหมายถึงไม่ จำกัด เฉพาะรายการนั้น ปัญหาก็คือวิธีการแยกความหมายแตกต่างกันเมื่อมากกว่าหนึ่งอาจจะต้อง (หรือแม้กระทั่งที่บันทึกไว้โดยไม่ได้ตั้งใจ)
แบรดโทมัส

คุณจะแนะนำให้ฉันสร้างตารางทางแยกแทนการใช้รหัสต่างประเทศแบบ null ได้หรือไม่?
ทอม

@Tom ใช่ฉันเชื่อว่ามันจะดีกว่าในกรณีนี้
Brad Thomas

@BradThomas - เพื่อหลีกเลี่ยงความกำกวมเดียวกันเมื่อใช้ตารางสี่แยกคุณจะเป็นตัวแทนของกรณีที่ 2 (เป็นที่ทราบกันว่านักเรียนไม่มีโรงเรียน) โดยบันทึกในตารางสี่แยกด้วย NULL School_ID หรือไม่
แอนดรู

1

ตารางฐานข้อมูลมีสิ่งที่ดีที่เรียกว่าข้อ จำกัด ดังนั้นมันจึงเป็นเรื่องง่ายมากที่จะทำในตารางสี่แยกที่อนุญาตให้นักเรียนเพียงคนเดียวเท่านั้นที่ปรากฏในตาราง แต่โรงเรียนหลายแห่งในตารางนั้น ได้อย่างมีประสิทธิภาพให้คุณ

ทฤษฎีเป็นสิ่งที่ดี แต่ในที่สุดคุณจะจำลองฐานข้อมูลของคุณหลังจากคำถามที่คุณถาม

หากคุณต้องการถามคำถามบ่อยๆด้วยคำถาม: "นักเรียนคนไหนที่อยู่ในโรงเรียนของฉัน" คุณต้องการสอบถามตารางนักเรียนทั้งหมดหรือมีตารางแยกง่าย

ในฐานข้อมูล: ปรับให้เหมาะสมสำหรับคำถามที่คุณถาม


0

มีกรณีการใช้งานที่ใช้ตารางที่สามอาจทำให้รู้สึกจริง ตัวอย่างอาจดูเหมือนสมมุติอย่างหมดจด แต่ฉันหวังว่ามันจะแสดงให้เห็นถึงจุดของฉันได้ดี สมมติว่าคุณเพิ่มคอลัมน์เพิ่มเติมลงในstudentsตารางและในบางกรณีคุณตัดสินใจที่จะบังคับใช้เอกลักษณ์ในระเบียนผ่านดัชนีคอมโพสิตในหลายคอลัมน์ มีโอกาสมากที่คุณจะต้องรวมschool_idคอลัมน์ไว้ด้วยและสิ่งต่างๆเริ่มที่จะยุ่งเหยิง เนื่องจาก SQL วิธีที่ได้รับการออกแบบแทรกระเบียนที่เหมือนกันหลายที่school_idเป็นNULLจะเป็นไปได้ มันทำให้รู้สึกที่สมบูรณ์แบบจากมุมมองทางเทคนิค แต่เป็นเรื่องง่ายและอาจนำไปสู่ผลลัพธ์ที่ไม่คาดคิด ในทางกลับกันการบังคับให้มีลักษณะเฉพาะในตารางสี่แยกนั้นเป็นเรื่องง่าย

ฉันต้องสร้างแบบจำลองความสัมพันธ์ "ทางเลือก" เมื่อเร็ว ๆ นี้ซึ่งข้อกำหนดสำหรับข้อ จำกัด ที่ไม่ซ้ำกันเกิดจากคอลัมน์การประทับเวลา การปล่อยคีย์ต่างประเทศที่ไม่สามารถใช้ได้ในตารางนั้นนำไปสู่ความเป็นไปได้ของการแทรกเร็กคอร์ดด้วยการประทับเวลาเดียวกัน (สมมติว่าเป็นค่าเริ่มต้นตั้งค่าในเร็กคอร์ดที่ยังไม่ได้รับการตรวจสอบ / อนุมัติ) และทางออกเดียวคือการลบ คอลัมน์ที่ไม่สามารถใช้ได้

อย่างที่คุณเห็นมันเป็นกรณีที่ค่อนข้างเฉพาะและอย่างที่คนอื่น ๆ สังเกตไว้ส่วนใหญ่คุณจะโอเคกับNULLค่าทั้งหมดอย่างสมบูรณ์ มันขึ้นอยู่กับข้อกำหนดเฉพาะของแบบจำลองของคุณ


0

นอกจากคำแนะนำที่ดีมากมายที่ได้ส่งไปแล้วโดยส่วนตัวแล้วฉันไม่ได้เป็นแฟนของคีย์ต่างประเทศยกเว้นว่าจำเป็นจริงๆ สิ่งแรกคือความสัมพันธ์ M: M ที่คุณกำลังอ้างอิง ยิ่งไปกว่านั้นการเรียกคีย์ต่างประเทศและการดึงข้อมูลตารางนั้นลงในคิวรีของคุณจะทำให้เกิดความซับซ้อนมากขึ้นและขึ้นอยู่กับขนาดของโต๊ะประสิทธิภาพที่ช้าลง ดังที่คนอื่นได้กล่าวไว้ว่าเขตข้อมูล FK nullable สามารถไม่ได้รับการสนับสนุนและสามารถสร้างปัญหาความสมบูรณ์ของข้อมูล

หากคุณกำลังกำหนดสถานะที่ไม่ทราบโรงเรียนของนักเรียนหรือว่างเปล่าค่า NULL จะไม่แยกแยะเงื่อนไขเหล่านั้น (อีกครั้งเรากลับไปที่ความถูกต้องของข้อมูล) การแนะนำตารางบทบาทโดย Tulains นั้นสง่างามและช่วยให้ค่า Null หมดจด

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