เหตุใดโมเดลเชิงสัมพันธ์สำหรับฐานข้อมูลจึงมีความสำคัญ


61

ฉันกำลังเข้าใกล้โครงการที่ฉันจะต้องใช้ฐานข้อมูลกับเจ้านายของฉัน เราเริ่มต้นเพียงเล็กน้อยเพื่อให้สภาพแวดล้อมการทำงานมีความเป็นส่วนตัวอย่างลึกซึ้ง

เขาให้ฐานข้อมูล บริษัท หนึ่งฐานแก่ฉันก่อนหน้านี้และตรงข้ามกับสิ่งที่ฉันได้รับการสอน (และอ่าน) ในโรงเรียนสำหรับ RDBMS ตัวอย่างเช่นมีฐานข้อมูลทั้งหมดที่นี่ซึ่งประกอบด้วยหนึ่งตาราง (ต่อฐานข้อมูลอิสระ) หนึ่งในตารางเหล่านั้นมีความยาว 20+ คอลัมน์และสำหรับบริบทนี่คือชื่อคอลัมน์บางส่วนจากตารางเดียว :

lngStoreID | vrStoreName | lngCompanyID | vrCompanyName | lngProductID | vrProductName

จุดที่เป็นที่ที่เขาควรจะมีตารางบุคคลที่เก็บข้อมูลกิจการ (ชื่อ, ขนาด, วันที่ซื้อ ฯลฯ ) เขาผลักมันทั้งหมดในตารางขนาดใหญ่หนึ่งต่อฐานข้อมูล

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

ทำไม schema เชิงสัมพันธ์ที่ดีจึงปรับปรุงฐานข้อมูล


33
หนึ่งคำ: การทำให้เป็นมาตรฐาน
Robert Harvey

9
ปิดผู้มีสิทธิเลือกตั้ง - ปรับตัวเอง! :-)
Robbie Dee

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

5
He [the boss] had given me one of his databases before and it completely went against what I was taught (and read about) in school for RDBMS<- ยินดีต้อนรับสู่โลกแห่งความจริง!
Möoz

5
ฉันนึกถึงการอ้างอิงฐานข้อมูลเชิงสัมพันธ์ที่ชื่นชอบ: "Normalize มันเจ็บ, denormalize จนกว่ามันจะทำงาน"
Jake

คำตอบ:


70

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

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

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


19
กรณีขอบที่สำคัญอย่างหนึ่งสำหรับ denormalization คือคลังข้อมูลโดยเฉพาะถ้าคุณมีข้อมูลจำนวนมากที่รับประกันว่าจะไม่เปลี่ยนแปลงและคุณต้องการสืบค้นอย่างรวดเร็วและมีประสิทธิภาพด้วยค่าใช้จ่ายของพื้นที่จัดเก็บ คำตอบที่ดีนี่เป็นเพียง FYI สำหรับมือใหม่ SQL ที่ไม่แน่ใจว่าทำไมสิ่งอื่นนอกจาก 3NF จึงเป็นที่ต้องการ


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

4
ย่อหน้าสุดท้ายนั้นควรเน้นเป็นตัวหนา :-) หากไม่มีการทำให้เป็นมาตรฐานมันเป็นไปไม่ได้ที่จะรับประกันความถูกต้องของข้อมูล การควบคุมการป้อนข้อมูล แต่เพียงผู้เดียวที่ชั้นตรรกะทางธุรกิจเป็นธุระของคนโง่เป็นทุกฐานข้อมูลที่ไม่ปกติในที่สุดการจัดแสดงนิทรรศการการเรียงลำดับของความผิดปกติข้อมูลบางอย่าง
DanK

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

24

ฉันจะต้องใช้ฐานข้อมูลกับเจ้านายของฉัน ...

การใช้ซอฟต์แวร์การจัดการฐานข้อมูลโดยเฉพาะอาจทำได้ง่ายกว่ามาก (ขออภัยไม่สามารถต้านทานได้)

lngStoreID | vrStoreName | lngCompanyID | vrCompanyName | lngProductID | vrProductName

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

แต่ ...

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

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

เป็นไปได้อย่างสมบูรณ์แบบในการสร้าง "มุมมองตารางเดี่ยว" ของข้อมูลด้วย ..


11
ความต้านทานต่อ weltanschauung ตารางเดียวมักจะมาจากผู้ที่ไม่มีประสบการณ์กับ SQL ที่ไม่เข้าใจการเข้าร่วม - โดยเฉพาะอย่างยิ่งเกี่ยวกับข้อมูลที่ขาดหายไปเช่นการรวมภายนอก
Robbie Dee

6
@ RobbieDee มากกว่าปกติมันมาจากคนที่เคยเห็นข้อมูลที่ผิดปกติได้รับความเสียหายจากการที่ไม่สอดคล้องกัน ฉันเป็นคนคนหนึ่ง ฉันจะพิจารณาโครงสร้างประเภทนี้ในสถานการณ์ที่ Phill แนะนำ: นี่เป็นตารางการบันทึก / การรายงานบางประเภทที่ข้อมูลจะไม่ถูกอัปเดตหรืออัปเดตโดยการล้างข้อมูลให้สะอาดและได้รับมาจากแหล่งอื่นอย่างสมบูรณ์
jpmc26

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

1
@Zach: ตกลงนั่นเป็นเหตุผลว่าทำไมบันทึกการขายอาจเป็นกรณีที่ยอมรับได้สำหรับเรื่องนี้ สมมติว่าคุณต้องการให้การขายแต่ละรายการเชื่อมโยงกับชื่อร้านค้าในเวลาที่ทำการขายไม่ใช่ "ชื่อปัจจุบันของร้านค้า" จากนั้นพยายาม "ทำให้ปกติ" สิ่งนี้ทำให้เกิดความซับซ้อนมากขึ้น (เนื่องจากชื่อร้านบันทึกตาราง จะต้องเป็นชุดเมื่อเวลาผ่านไปไม่เพียงหนึ่งค่าต่อ storeid)
Steve Jessop

บางทีกฎของหัวแม่มืออาจเป็นไปได้ว่าหากความซับซ้อนเพียงอย่างเดียวที่นำเสนอโดยการนอร์มัลไลเซชั่นที่เสนอก็คือตอนนี้มีบางคำถามที่ต้องการรวมเข้าด้วยกันเพื่อเลือกคอลัมน์ทั้งหมดที่พวกเขาต้องการรายงาน )
Steve Jessop

14

ทำไม schema เชิงสัมพันธ์ที่ดีจึงปรับปรุงฐานข้อมูล

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

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

กฎ 3NF สร้างความสัมพันธ์ระหว่างข้อมูลที่ "ปรับปรุง" ฐานข้อมูล:

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

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

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

  4. โครงสร้างฐานข้อมูลที่เหมาะสมนำไปสู่การปรับปรุงประสิทธิภาพโดยการเชื่อมต่อข้อมูลด้วยวิธีการลดการจัดเก็บข้อมูลลดการเรียกหน่วยเก็บเพื่อดึงข้อมูลเพิ่มทรัพยากรในหน่วยความจำสูงสุดและ / หรือลดการเรียงลำดับ / การจัดการข้อมูลสำหรับชุดข้อมูลเฉพาะที่คุณมี ดำเนินการกับมัน แต่โครงสร้าง "เหมาะสม" ขึ้นอยู่กับปริมาณของข้อมูลลักษณะของข้อมูลชนิดของการสืบค้นทรัพยากรระบบ ฯลฯ โดยการทำให้มาตรฐานเป็นปกติคุณอาจทำให้ประสิทธิภาพแย่ลง (เช่นถ้าคุณโหลดข้อมูลทั้งหมดเป็น 1 ตาราง - การเข้าร่วมอาจทำให้ช้าลง แบบสอบถาม) การประมวลผลธุรกรรม (OLTP) กับระบบธุรกิจอัจฉริยะ (คลังข้อมูล) แตกต่างกันมาก

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

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

โชคดี!


4
Unmentioned แต่ฉันคิดว่าจุดสำคัญสำหรับโปรแกรมเมอร์คือการแก้ไข "สิ่ง" หนึ่งอย่างต้องแก้ไขเพียงแถวเดียวแทนที่จะต้องวนรอบฐานข้อมูลทั้งหมดเพื่อค้นหาและแทนที่สิ่งเดียว
slebetman

@slebetman คุณไม่ควรมีลูปด้านโค้ดเพื่ออัปเดตหลายแถวในตารางเดียวไม่ว่าจะเป็นมาตรฐานหรือไม่ ใช้WHEREประโยค แน่นอนสิ่งเหล่านี้ยังคงผิดพลาด แต่มีโอกาสน้อยกว่าในสถานการณ์ปกติเนื่องจากคุณต้องจับคู่หนึ่งแถวผ่านคีย์หลักเท่านั้น
jpmc26

@ jpmc26: การวนลูปฐานข้อมูลหมายถึงการสร้างเคียวรีเพื่ออัพเดตแถวที่ได้รับผลกระทบทั้งหมด บางครั้งที่เดียวก็พอ แต่ฉันเห็นโครงสร้างที่ไม่บริสุทธิ์ซึ่งต้องการการเลือกย่อยในตารางเดียวกันเพื่อรับแถวที่ได้รับผลกระทบทั้งหมดโดยไม่กระทบกับแถวที่ไม่ควรเปลี่ยน ผมเคยเห็นแม้แต่โครงสร้างที่คำเดียวไม่สามารถทำงาน (หน่วยงานที่ต้องการการเปลี่ยนแปลงที่อยู่ในคอลัมน์ที่แตกต่างกันขึ้นอยู่กับแถว)
slebetman

คำตอบที่ยอดเยี่ยมมากมายสำหรับคำถามนี้และนี่ก็ไม่มีข้อยกเว้น
Mike Chamberlain

11

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

Teams
Id | Name | HomeCity

Games
Id | StartsAt | HomeTeamId | AwayTeamId | Location

และฐานข้อมูลตารางเดียวจะมีลักษณะเช่นนี้

TeamsAndGames
Id | TeamName | TeamHomeCity | GameStartsAt | GameHomeTeamId | GameAwayTeamId | Location

อันดับแรกให้ดูที่การสร้างดัชนีบนตารางเหล่านั้น ถ้าฉันต้องการดัชนีในบ้านเกิดของทีมฉันสามารถเพิ่มลงในTeamsตารางหรือTeamsAndGamesตารางได้อย่างง่ายดาย โปรดจำไว้ว่าเมื่อใดก็ตามที่คุณสร้างดัชนีจำเป็นต้องจัดเก็บไว้ในดิสก์บางแห่งและอัปเดตเมื่อมีการเพิ่มแถวลงในตาราง ในกรณีของTeamsตารางนี้ค่อนข้างตรงไปตรงมา ฉันใส่ทีมใหม่ฐานข้อมูลจะอัพเดตดัชนี แต่จะเกี่ยวกับTeamsAndGamesอะไร ก็เช่นเดียวกันกับจากTeamsตัวอย่าง. ฉันเพิ่มทีมดัชนีได้รับการปรับปรุง แต่มันก็เกิดขึ้นเมื่อฉันเพิ่มเกม! แม้ว่าฟิลด์นั้นจะเป็นโมฆะสำหรับเกม แต่ดัชนียังต้องมีการอัปเดตและเก็บไว้ในดิสก์สำหรับเกมนั้น สำหรับดัชนีเดียวสิ่งนี้ไม่ได้ฟังดูแย่นัก แต่เมื่อคุณต้องการดัชนีจำนวนมากสำหรับเอนทิตีหลายอันที่อัดแน่นในตารางนี้คุณเสียพื้นที่จำนวนมากในการจัดเก็บดัชนีและเวลาประมวลผลจำนวนมากที่อัพเดตพวกเขาสำหรับสิ่งที่พวกเขาไม่ได้ใช้

ประการที่สองความสอดคล้องของข้อมูล ในกรณีที่ใช้สองตารางแยกกันฉันสามารถใช้คีย์ต่างประเทศจากGamesตารางไปยังTeamsตารางเพื่อกำหนดว่าทีมใดกำลังเล่นในเกม และสมมติว่าฉันสร้างHomeTeamIdและAwayTeamIdคอลัมน์ไม่เป็นโมฆะฐานข้อมูลจะทำให้แน่ใจว่าทุกเกมที่ฉันใส่มี 2 ทีมและทีมเหล่านั้นมีอยู่ในฐานข้อมูลของฉัน แต่สิ่งที่เกี่ยวกับสถานการณ์ตารางเดียว? ดีเนื่องจากมีหลายเอนทิตีในตารางนี้คอลัมน์เหล่านั้นควรเป็นโมฆะ (คุณสามารถทำให้พวกมันไม่เป็นโมฆะและผลักข้อมูลขยะในนั้น แต่นั่นเป็นเพียงความคิดที่น่ากลัว) หากคอลัมน์เหล่านั้นเป็นโมฆะฐานข้อมูลจะไม่สามารถรับประกันได้ว่าเมื่อคุณแทรกเกมที่มีสองทีม

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

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

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

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

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

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


1
"ทีม: Id | ชื่อ | HomeCity" เพียงตรวจสอบให้แน่ใจว่าสคีมาข้อมูลของคุณไม่ได้ทำให้แอปพลิเคชันของคุณไม่ถูกต้องอ้างว่า Super Bowl XXXIV ได้รับรางวัลจาก LA Rams ในขณะที่ SB XXXIV ควรปรากฏในข้อความค้นหาสำหรับการแข่งขันชิงแชมป์ทั้งหมดที่ทีมปัจจุบันรู้จักในชื่อ LA Rams มี "โต๊ะพระเจ้า" ที่ดีกว่าและแย่ลงและคุณได้นำเสนอสิ่งที่ไม่ดีอย่างแน่นอน สิ่งที่ดีกว่าก็คือ "รหัสเกม | ชื่อทีมในบ้าน | ทีมในเมือง | ชื่อทีมที่อยู่ | ทีมที่อยู่ห่างออกไปในเมือง | เกมเริ่มต้นที่ | etc ... " ซึ่งมาเกี่ยวกับความพยายามครั้งแรกในการสร้างแบบจำลองข้อมูลเช่น "New Orleans Saints @ Chicago Bears 1p Eastern"
Steve Jessop

6

ใบเสนอราคาของวัน: " ทฤษฎีและการปฏิบัติควรเหมือนกัน ... ในทฤษฎี "

โต๊ะปรับสภาพ

ตาราง hold-it-all ที่ไม่ซ้ำกันของคุณมีข้อมูลที่ซ้ำซ้อนมีข้อดีอย่างหนึ่ง: ทำให้การรายงานบนบรรทัดของมันง่ายมากในการเขียนโค้ดและดำเนินการอย่างรวดเร็วเนื่องจากคุณไม่ต้องเข้าร่วมใด ๆ แต่สิ่งนี้มีค่าใช้จ่ายสูง:

  • มันมีสำเนาของความสัมพันธ์ที่ซ้ำซ้อน (เช่นIngCompanyIDและvrCompanyName) การอัพเดตข้อมูลหลักอาจจำเป็นต้องอัพเดตหลายบรรทัดมากกว่าในสคีมาปกติ
  • มันผสมทุกอย่าง คุณไม่สามารถควบคุมการเข้าถึงได้ง่ายในระดับฐานข้อมูลเช่นสร้างความมั่นใจว่าผู้ใช้ A สามารถอัปเดตเฉพาะข้อมูล บริษัท และข้อมูลผลิตภัณฑ์เท่านั้นสำหรับผู้ใช้ B
  • คุณไม่สามารถตรวจสอบกฎความมั่นคงในระดับฐานข้อมูล (เช่นคีย์หลักเพื่อบังคับใช้ว่ามีชื่อ บริษัท เดียวสำหรับ id บริษัท )
  • คุณไม่ได้รับประโยชน์อย่างเต็มที่จากเครื่องมือเพิ่มประสิทธิภาพฐานข้อมูลที่สามารถระบุกลยุทธ์การเข้าถึงที่ดีที่สุดสำหรับการสืบค้นที่ซับซ้อนโดยใช้ประโยชน์จากขนาดของตารางปกติและสถิติของดัชนีหลายดัชนี สิ่งนี้อาจชดเชยผลประโยชน์ที่ จำกัด ในการหลีกเลี่ยงการเข้าร่วมอย่างรวดเร็ว

ตารางมาตรฐาน

ข้อเสียข้างต้นเป็นข้อได้เปรียบสำหรับสคีมาปกติ แน่นอนว่าการสืบค้นอาจซับซ้อนกว่าการเขียนเล็กน้อย

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


5

ฉันคิดว่าคำถามของคุณมีอย่างน้อยสองส่วน:

1. เหตุใดจึงไม่ควรจัดเก็บเอนทิตีประเภทต่าง ๆ ไว้ในตารางเดียวกัน

คำตอบที่สำคัญที่สุดที่นี่คือการอ่านรหัสและความเร็ว A SELECT name FROM companies WHERE id = ?อ่านได้ง่ายกว่าSELECT companyName FROM masterTable WHERE companyId = ?และคุณมีโอกาสน้อยที่จะค้นหาเรื่องไร้สาระโดยไม่ตั้งใจ (เช่นSELECT companyName FROM masterTable WHERE employeeId = ?จะไม่สามารถทำได้เมื่อ บริษัท และพนักงานถูกเก็บไว้ในตารางที่แตกต่างกัน) สำหรับความเร็วข้อมูลจากตารางฐานข้อมูลจะถูกเรียกคืนโดยการอ่านตารางเต็มตามลำดับหรือโดยการอ่านจากดัชนี ทั้งสองจะเร็วขึ้นหากตาราง / ดัชนีมีข้อมูลน้อยลงและเป็นกรณีที่ข้อมูลถูกเก็บไว้ในตารางต่าง ๆ (และคุณจำเป็นต้องอ่านหนึ่งในตาราง / ดัชนีเท่านั้น)

2. เหตุใดจึงควรแบ่งเอนทิตีประเภทเดียวเป็นเอนทิตีย่อยที่จัดเก็บในตารางที่แตกต่างกัน

นี่คือเหตุผลส่วนใหญ่เพื่อป้องกันข้อมูลไม่สอดคล้องกัน ด้วยวิธีการแบบตารางเดี่ยวสำหรับระบบการจัดการคำสั่งซื้อคุณอาจเก็บชื่อลูกค้าที่อยู่ลูกค้าและรหัสผลิตภัณฑ์ของผลิตภัณฑ์ที่ลูกค้าสั่งซื้อเป็นเอนทิตีเดียว หากลูกค้าสั่งซื้อผลิตภัณฑ์หลายรายการคุณจะมีชื่อและที่อยู่ของลูกค้าหลายรายการในฐานข้อมูลของคุณ ในกรณีที่ดีที่สุดคุณเพิ่งได้รับข้อมูลซ้ำในฐานข้อมูลซึ่งอาจทำให้ข้อมูลช้าลงเล็กน้อย แต่กรณีที่แย่กว่านั้นคือมีคน (หรือบางรหัส) ทำผิดพลาดเมื่อป้อนข้อมูลเพื่อให้ บริษัท ต่างๆมีที่อยู่ที่แตกต่างกันในฐานข้อมูลของคุณ สิ่งนี้ไม่ดีพอ แต่ถ้าคุณจะสอบถามที่อยู่ของ บริษัท ตามชื่อของมัน (เช่นSELECT companyAddress FROM orders WHERE companyName = ? LIMIT 1) คุณเพียงแค่ได้รับหนึ่งในสองที่อยู่ที่ส่งคืนและจะไม่ได้ตระหนักว่ามีความไม่สอดคล้องกัน แต่ทุกครั้งที่คุณเรียกใช้แบบสอบถามคุณอาจได้รับที่อยู่ที่แตกต่างกันจริงขึ้นอยู่กับวิธีแก้ไขแบบสอบถามของคุณภายใน DBMS การทำเช่นนี้อาจทำให้แอปพลิเคชั่นของคุณแตกต่างจากที่อื่นและสาเหตุของการแตกหักนั้นยากที่จะค้นหา

ด้วยวิธีการหลายตารางคุณจะรู้ว่ามีการพึ่งพาการทำงานจากชื่อ บริษัท ไปยังที่อยู่ บริษัท (หาก บริษัท สามารถมีที่อยู่เดียวเท่านั้น) คุณจะต้องเก็บ tuple (companyName, companyAddress) ไว้ในตารางเดียว (เช่นcompany) และ tuple (productId, companyName) ในอีกตารางหนึ่ง (เช่นorder) UNIQUEจำกัด บนcompanyโต๊ะก็จะบังคับให้แต่ละ บริษัท เดียวที่มีที่อยู่เดียวในฐานข้อมูลของคุณเพื่อให้ความไม่สอดคล้องกันสำหรับที่อยู่ที่ บริษัท ไม่เคยได้เกิดขึ้น

หมายเหตุ: ในทางปฏิบัติสำหรับเหตุผลด้านประสิทธิภาพคุณอาจสร้าง companyId ที่ไม่ซ้ำกันสำหรับแต่ละ บริษัท และใช้เป็น foreign key แทนการใช้ companyName โดยตรง แต่วิธีการทั่วไปยังคงเหมือนเดิม


3

TL; DR - พวกเขากำลังออกแบบฐานข้อมูลตามวิธีการที่พวกเขาได้รับการสอนเมื่อพวกเขาอยู่ในโรงเรียน

ฉันน่าจะเขียนคำถามนี้เมื่อ 10 ปีก่อน ฉันใช้เวลาพอสมควรที่จะเข้าใจว่าทำไมรุ่นก่อนของฉันจึงออกแบบฐานข้อมูลในแบบที่พวกเขาทำ คุณกำลังทำงานกับใครบางคนที่:

  1. ได้รับทักษะการออกแบบฐานข้อมูลส่วนใหญ่โดยใช้ Excel เป็นฐานข้อมูลหรือ
  2. พวกเขากำลังใช้แนวปฏิบัติที่ดีที่สุดเมื่อพวกเขาออกจากโรงเรียน

ฉันไม่สงสัยว่าเป็นอันดับ 1 เนื่องจากคุณมีหมายเลขประจำตัวในตารางของคุณดังนั้นฉันจะถือว่า # 2

หลังจากที่ฉันออกจากโรงเรียนฉันทำงานให้กับร้านที่ใช้AS / 400 (aka IBM i) ฉันพบสิ่งแปลก ๆ ในวิธีที่พวกเขาออกแบบฐานข้อมูลของพวกเขาและเริ่มสนับสนุนเราทำการเปลี่ยนแปลงตามวิธีที่ฉันสอนวิธีการออกแบบฐานข้อมูล (ตอนนั้นฉันก็โง่แล้ว)

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

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


ตัวอย่างบางส่วนของสิ่งที่ฉันพบที่ไม่ตรงกับโมเดลเชิงสัมพันธ์:

  • วันที่ถูกเก็บเป็นตัวเลขวันจูเลียนซึ่งต้องการการเข้าร่วมในตารางวันที่เพื่อรับวันจริง
  • Denormalized tables ที่มีคอลัมน์เรียงตามประเภทเดียวกัน (เช่นcode1,code2, ..., code20)
  • คอลัมน์ CHAR ความยาว NxM แสดงอาร์เรย์ของสตริง N ความยาว M

เหตุผลที่ฉันได้รับจากการตัดสินใจออกแบบนั้นขึ้นอยู่กับข้อ จำกัด ของระบบเมื่อฐานข้อมูลถูกออกแบบครั้งแรก

วันที่ - ฉันได้รับแจ้งว่าต้องใช้เวลาในการประมวลผลมากขึ้นในการใช้ฟังก์ชั่นวันที่ (เดือนหรือวันหรือวันทำงาน) ในการประมวลผลวันที่มากกว่าที่จะสร้างตารางของวันที่ที่เป็นไปได้ทั้งหมดพร้อมข้อมูลทั้งหมด

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

ความยาว NxM คอลัมน์ CHAR - เป็นการง่ายกว่าที่จะผลักค่าการกำหนดค่าเป็นหนึ่งคอลัมน์เพื่อลดการดำเนินการอ่านไฟล์

ตัวอย่างที่เข้าใจได้ไม่ดีใน C เทียบเท่าเพื่อสะท้อนสภาพแวดล้อมการเขียนโปรแกรมที่พวกเขามี:

#define COURSE_LENGTH 4
#define NUM_COURSES 4
#define PERIOD_LENGTH 2

struct mytable {
    int id;
    char periodNames[NUM_COURSES * PERIOD_LENGTH];  // NxM CHAR Column
    char course1[COURSE_LENGTH];
    char course2[COURSE_LENGTH];
    char course3[COURSE_LENGTH];
    char course4[COURSE_LENGTH];
};

...

// Example row
struct mytable row = {.id= 1, .periodNames="HRP1P2P8", .course1="MATH", .course2="ENGL", .course3 = "SCI ", .course4 = "READ"};

char *courses; // Pointer used to access the sequential columns
courses = (char *)&row.course1;


for(int i = 0; i < NUM_COURSES; i++) {

    printf("%d: %.*s -> %.*s\n",i+1, PERIOD_LENGTH, &row.periodNames[PERIOD_LENGTH * i], COURSE_LENGTH,&courses[COURSE_LENGTH*i]);
}

เอาท์พุท

1: HR -> MATH
2: P1 -> ENGL
3: P2 -> SCI
4: P8 -> READ

ตามที่ฉันบอกบางสิ่งนี้ถือว่าเป็นแนวปฏิบัติที่ดีที่สุดในเวลานั้น

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