การใช้ชนิดย่อยของชนิดย่อยในรูปแบบการออกแบบชนิด / ชนิดย่อยที่มีคลาสย่อยเฉพาะซึ่งกันและกัน


20

บทนำ

เพื่อให้คำถามนี้มีประโยชน์สำหรับผู้อ่านในอนาคตฉันจะใช้ตัวแบบข้อมูลทั่วไปเพื่อแสดงปัญหาที่ฉันเผชิญ

รูปแบบข้อมูลของเราประกอบด้วย 3 หน่วยงานซึ่งจะต้องได้รับการระบุว่าเป็นA, และB Cเพื่อให้ทุกอย่างง่ายขึ้นคุณลักษณะทั้งหมดของพวกเขาจะเป็นintประเภท

Entity Aมีแอตทริบิวต์ต่อไปนี้: D, EและX;

Entity Bมีแอตทริบิวต์ต่อไปนี้: D, EและY;

เอนทิตีCมีคุณสมบัติดังต่อไปนี้: DและZ;

เนื่องจากเอนทิตีทั้งหมดใช้แอตทริบิวต์ร่วมกันDฉันจึงตัดสินใจใช้การออกแบบชนิด / ชนิดย่อย

ข้อสำคัญ: เอนทิตีเป็นเอกสิทธิ์เฉพาะบุคคล! หมายความว่าเอนทิตีนั้นเป็น A หรือ B หรือ C

ปัญหา:

หน่วยงานAและBมีอีกแอตทริบิวต์ทั่วไปแต่แอตทริบิวต์นี้ไม่ได้อยู่ในกิจการEC

คำถาม:

ฉันต้องการใช้คุณลักษณะที่อธิบายข้างต้นเพื่อเพิ่มประสิทธิภาพการออกแบบของฉันถ้าเป็นไปได้

ความจริงแล้วฉันไม่รู้ว่าจะทำอย่างไรและจะเริ่มต้นอย่างไรจึงจะโพสต์นี้

คำตอบ:


6

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

ฉันเห็นด้วยอย่างสมบูรณ์กับคะแนนของ Remusเกี่ยวกับ:

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

ดังที่กล่าวไว้ตัวเลือกที่คุณต้องเผชิญมีดังต่อไปนี้เรียงตามลำดับอย่างน้อยที่สุดเพื่อทำให้เป็นมาตรฐานมากที่สุด:

  • การโปรโมตคุณสมบัติEไปยังตารางชนิดฐาน
  • เก็บไว้ในตารางย่อยหลายประเภท
  • normalizing อย่างเต็มที่Eออกไปยังตารางย่อยใหม่ตัวกลางในระดับเดียวกันกับCที่AและBจะเป็นชั้นย่อยโดยตรง ( คำตอบของ @ MDCCL )

ลองดูที่แต่ละตัวเลือก:

ย้ายคุณสมบัติEไปที่ตารางชนิดฐาน

ข้อดี

  • ความซับซ้อนของแบบสอบถามที่ลดลงสำหรับคำสั่งที่จำเป็นEแต่ไม่X, หรือYZ
  • ที่อาจเกิดขึ้นมีประสิทธิภาพมากขึ้นสำหรับการค้นหาที่ต้องการEแต่ไม่X, YหรือZ(คำสั่งรวมโดยเฉพาะอย่างยิ่ง) เนื่องจากไม่เข้าร่วม
  • มีแนวโน้มที่จะสร้างดัชนีใน(D, E)(และถ้าเป็นเช่นนั้นอาจเป็นดัชนีที่มีตัวกรอง(D, E)ที่ซึ่ง EntityType <> Cหากเงื่อนไขดังกล่าวได้รับอนุญาต)

ข้อเสีย

  • ไม่สามารถทำเครื่องหมายEว่าNOT NULL
  • ต้องการเพิ่มCHECK CONSTRAINTในตารางชนิดฐานเพื่อให้แน่ใจว่าE IS NULLเมื่อ EntityType = C(แม้ว่านี่ไม่ใช่ปัญหาใหญ่)
  • จำเป็นต้องให้ความรู้แก่ผู้ใช้แบบจำลองข้อมูลว่าทำไมEต้องNULLและควรได้รับการละเว้นอย่างสิ้นเชิงเมื่อ EntityType C=
  • ประสิทธิภาพน้อยลงเล็กน้อยเมื่อEเป็นประเภทความยาวคงที่และส่วนใหญ่ของแถวสำหรับ EntityType ของC(เช่นไม่ใช้Eจึงเป็นNULL) และไม่ใช้SPARSEตัวเลือกในคอลัมน์หรือการบีบอัดข้อมูลในดัชนีแบบกลุ่ม
  • อาจมีประสิทธิภาพน้อยลงสำหรับแบบสอบถามที่ไม่ต้องการEเนื่องจากการมีอยู่Eในตารางประเภทฐานจะเพิ่มขนาดของแต่ละแถวซึ่งจะลดจำนวนแถวที่สามารถพอดีกับหน้าข้อมูล แต่สิ่งนี้จะขึ้นอยู่กับประเภทข้อมูลที่แน่นอนของEFILLFACTOR จำนวนแถวที่อยู่ในตารางประเภทฐาน ฯลฯ

เก็บคุณสมบัติไว้Eในตารางย่อยแต่ละประเภท

ข้อดี

  • รูปแบบข้อมูลที่สะอาดกว่า (เช่นไม่ต้องกังวลเกี่ยวกับการให้ความรู้แก่ผู้อื่นว่าทำไมคอลัมน์Eในตารางประเภทฐานไม่ควรใช้เพราะ "ไม่มีอยู่จริง"
  • อาจคล้ายกับโมเดลวัตถุมากขึ้น
  • สามารถทำเครื่องหมายคอลัมน์ราวกับNOT NULLว่านี่เป็นคุณสมบัติที่ต้องการของเอนทิตี
  • ไม่จำเป็นต้องเสริมCHECK CONSTRAINTบนตารางชนิดฐานเพื่อให้แน่ใจว่าE IS NULLเมื่อ EntityType = C(แม้ว่านี่จะไม่ได้รับมาก)

ข้อเสีย

  • ต้องใช้ JOIN เพื่อตารางย่อยเพื่อรับคุณสมบัตินี้
  • อาจมีประสิทธิภาพน้อยลงเล็กน้อยเมื่อต้องการEเนื่องจาก JOIN ขึ้นอยู่กับจำนวนของA+ แถวที่Bคุณมีเมื่อเทียบกับจำนวนแถวที่Cมี
  • ยากขึ้น / ซับซ้อนขึ้นเล็กน้อยสำหรับการดำเนินการที่เกี่ยวข้องกับเอนทิตีAและB(และไม่ใช่ C ) เพียงอย่างเดียวว่าเป็น "ประเภท" เดียวกัน แน่นอนคุณสามารถนามธรรมนี้ผ่านทางมุมมองที่ไม่UNION ALLระหว่างSELECTของตารางสำหรับเข้าร่วมAและอีกของตารางที่สมัครสมาชิกสำหรับSELECT Bซึ่งจะลดความซับซ้อนของการสืบค้น SELECT แต่ไม่เป็นประโยชน์สำหรับINSERTและการUPDATEสืบค้น
  • ขึ้นอยู่กับแบบสอบถามที่เฉพาะเจาะจงและความถี่ในการดำเนินการซึ่งอาจเป็นความไร้ประสิทธิภาพที่อาจเกิดขึ้นในกรณีที่มีดัชนีบน(D, E)จะช่วยจริงแบบสอบถามที่ใช้อย่างน้อยหนึ่งแบบสอบถามเนื่องจากพวกเขาไม่สามารถจัดทำดัชนีร่วมกัน

ทำให้มาตรฐานEเป็นตารางกลางระหว่างคลาสพื้นฐานและA&B

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

ข้อดี

  • โมเดลข้อมูลถูกทำให้เป็นมาตรฐานอย่างสมบูรณ์ (ไม่มีสิ่งใดผิดปกติกับสิ่งนี้เนื่องจากเป็นสิ่งที่ RDBMS ถูกออกแบบมาให้ทำ)
  • ลดความซับซ้อนของข้อความค้นหาสำหรับแบบสอบถามที่ต้องการAและBแต่ไม่C(คือไม่จำเป็นต้องมีสองแบบสอบถามเข้าร่วมผ่านUNION ALL)

ข้อเสีย

  • ใช้พื้นที่เพิ่มขึ้นเล็กน้อย ( Barตารางจะทำซ้ำ ID และมีคอลัมน์ใหม่BarTypeCode) [เล็กน้อย แต่สิ่งที่ควรระวัง]
  • เพิ่มความซับซ้อนของการสืบค้นเล็กน้อยเนื่องจากต้องการการเพิ่มเติมJOINเพื่อไปยังAหรือB
  • เพิ่มพื้นที่ผิวสำหรับล็อคส่วนใหญ่เปิดINSERT( DELETEสามารถจัดการโดยนัยผ่านการทำเครื่องหมาย Foreign Keys as ON CASCADE DELETE) เนื่องจากการทำธุรกรรมจะถูกเปิดขึ้นอีกเล็กน้อยบนตารางระดับฐานเล็กน้อย (เช่นFoo) [เล็กน้อยมาก แต่สิ่งที่ต้องระวัง]
  • ไม่มีความรู้โดยตรงของประเภทจริง - AหรือB- ภายในตารางฐานชั้น, Foo; รู้เพียงชนิดเท่านั้นBrซึ่งอาจเป็นAหรือB:

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

  • ไม่มีวิธีการที่สอดคล้องกันในการโต้ตอบกับA& Bvs C:

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

  • อาจปรับตัวน้อยลงกับกฎเกณฑ์ทางธุรกิจที่เปลี่ยนแปลงตลอดเวลา:

    ความหมายสิ่งต่าง ๆ เปลี่ยนแปลงอยู่เสมอและมันก็ค่อนข้างง่ายที่จะเลื่อนEขึ้นไปที่ตารางระดับฐานถ้ามันกลายเป็นเรื่องธรรมดาไปยังทุกประเภทย่อย นอกจากนี้ยังง่ายพอที่จะย้ายคุณสมบัติทั่วไปออกไปยังประเภทย่อยหากการเปลี่ยนแปลงในลักษณะของเอนทิตีทำให้การเปลี่ยนแปลงที่คุ้มค่า มันง่ายพอที่จะแบ่งย่อยเป็นสองประเภทย่อย (เพียงแค่สร้างSubTypeIDค่าอื่น) หรือรวมสองประเภทย่อยเป็นหนึ่ง ตรงกันข้ามจะเกิดอะไรขึ้นถ้าEภายหลังกลายเป็นทรัพย์สินส่วนกลางของประเภทย่อยทั้งหมด? จากนั้นเลเยอร์ตัวกลางของBarตารางจะไม่มีความหมายและความซับซ้อนที่เพิ่มเข้ามาจะไม่คุ้มค่า แน่นอนว่าเป็นไปไม่ได้ที่จะทราบว่าการเปลี่ยนแปลงดังกล่าวจะเกิดขึ้นใน 5 หรือ 10 ปีดังนั้นBarตารางจึงไม่จำเป็นหรือเป็นไปได้สูงที่จะเป็นความคิดที่ไม่ดี (ซึ่งเป็นสาเหตุที่ฉันพูดว่า " อาจปรับตัวได้น้อยลง") นี่เป็นเพียงจุดที่ต้องพิจารณา มันเป็นการพนันในทิศทางใดทิศทางหนึ่ง

  • การจัดกลุ่มที่ไม่เหมาะสมอาจเป็นไปได้:

    ความหมายเพียงเพราะEทรัพย์สินนั้นใช้ร่วมกันระหว่างประเภทเอนทิตีAและBไม่ได้หมายความว่าAและB ควรจัดกลุ่มเข้าด้วยกัน เพียงเพราะสิ่งที่ "ดู" เหมือนกัน (เช่นคุณสมบัติเดียวกัน) ไม่ได้หมายความว่าพวกเขาเหมือนกัน

สรุป

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

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

ฉันคิดว่าฉันมักจะเริ่มต้นที่จะเก็บไว้Eในตารางย่อยแยกเพราะอย่างน้อยที่สุด "สะอาด" ฉันจะพิจารณาย้ายEไปยังตารางประเภทฐาน IF: แถวส่วนใหญ่ไม่ได้มีไว้สำหรับ EntityType ของC; และจำนวนแถวเป็นอย่างน้อยเป็นล้าน และฉันบ่อยครั้งกว่าที่ไม่ได้ดำเนินการแบบสอบถามที่ต้องการEและ / หรือแบบสอบถามที่จะได้รับประโยชน์จากดัชนีใน(D, E)การดำเนินการบ่อยครั้งมากและ / หรือต้องการทรัพยากรระบบเพียงพอเช่นที่ดัชนีมีลดการใช้ทรัพยากรโดยรวมหรืออย่างน้อยป้องกัน ไฟกระชากในการใช้ทรัพยากรที่สูงกว่าระดับที่ยอมรับได้หรือนานพอที่จะทำให้เกิดการบล็อกมากเกินไปและ / หรือเพิ่มการหยุดชะงัก


UPDATE

OP แสดงความคิดเห็นกับคำตอบนี้ว่า:

นายจ้างของฉันเปลี่ยนตรรกะทางธุรกิจโดยลบ E ทั้งหมด!

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

ทรัพยากรไม่ได้ไม่มีที่สิ้นสุดไม่เพียง แต่ CPU / Disk / RAM แต่ยังรวมถึงการพัฒนาทรัพยากร: เวลาและเงิน ธุรกิจกำลังจัดลำดับความสำคัญของโครงการอย่างต่อเนื่องเพราะทรัพยากรเหล่านั้นมี จำกัด และบ่อยครั้งที่ (อย่างน้อยก็ในประสบการณ์ของฉัน) โครงการเพื่อเพิ่มประสิทธิภาพ (ทั้งประสิทธิภาพของระบบรวมถึงการพัฒนาที่เร็วขึ้น / ข้อบกพร่องที่น้อยลง) ได้รับการจัดลำดับความสำคัญต่ำกว่าโครงการที่เพิ่มฟังก์ชันการทำงาน ในขณะที่มันเป็นที่น่าผิดหวังสำหรับเราคนทางเทคนิคเพราะเราเข้าใจว่าผลประโยชน์ระยะยาวของโครงการ refactoring คือมันเป็นเพียงลักษณะของธุรกิจที่ธุรกิจทางเทคนิคน้อยคนมีเวลาได้ง่ายขึ้นเห็นความสัมพันธ์โดยตรงระหว่างฟังก์ชั่นใหม่และใหม่ รายได้ สิ่งนี้ทำให้เกิดความเดือดร้อน: "เราจะกลับมาแก้ไขในภายหลัง" == "

โดยที่ในใจถ้าขนาดของข้อมูลมีขนาดเล็กพอที่การเปลี่ยนแปลงนั้นสามารถทำการสืบค้นได้มากและ / หรือคุณมีหน้าต่างการบำรุงรักษาที่ยาวพอที่จะไม่เพียง แต่ทำการเปลี่ยนแปลง แต่ยังย้อนกลับถ้ามีบางอย่างเกิดขึ้น ผิดแล้ว normalizing Eออกไปตารางตัวกลางระหว่างตารางฐานชั้นและAและBชั้นย่อยตารางสามารถทำงานได้ ( แต่ที่ยังคงใบคุณมีความรู้โดยตรงของประเภทที่เฉพาะเจาะจง ( AหรือB) ในตารางระดับฐาน) แต่ถ้าคุณมีหลายร้อยล้านแถวในตารางเหล่านี้และโค้ดจำนวนมากที่อ้างถึงตาราง (รหัสที่จะต้องมีการทดสอบเมื่อมีการเปลี่ยนแปลง) มันมักจะจ่ายเงินให้เป็นประโยชน์มากกว่าอุดมคติ และนี่คือสภาพแวดล้อมที่ฉันต้องรับมือเป็นเวลาหลายปี: 987 ล้านแถว & 615 GB ในตารางระดับฐานซึ่งกระจายไปทั่วเซิร์ฟเวอร์ 18 แห่ง และรหัสจำนวนมากก็กระทบกับตารางเหล่านี้ (ตารางฐานและตารางย่อย) ว่ามีความต้านทานมากมาย - ส่วนใหญ่มาจากการจัดการ แต่บางครั้งจากส่วนที่เหลือของทีมไปจนถึงการเปลี่ยนแปลงใด ๆ เนื่องจากปริมาณการพัฒนาและ ทรัพยากร QA ที่จะต้องจัดสรร

ดังนั้นอีกครั้งวิธี "ที่ดีที่สุด" สามารถถูกกำหนดสถานการณ์โดยสถานการณ์: คุณจำเป็นต้องรู้ระบบของคุณ (เช่นข้อมูลเท่าใดและวิธีการที่ตารางและรหัสทั้งหมดที่เกี่ยวข้อง) วิธีการบรรลุ refactoring และผู้คน คุณทำงานร่วมกับ (ทีมของคุณและผู้บริหารที่เป็นไปได้ - คุณจะได้รับการเข้าร่วมโครงการดังกล่าวหรือไม่) มีการเปลี่ยนแปลงบางอย่างที่ฉันได้พูดถึงและวางแผนมาเป็นเวลา 1 - 2 ปีและใช้เวลาวิ่งหลายครั้ง / ปล่อยเพื่อให้ได้ 85% ของการใช้ แต่ถ้าคุณมี <1 ล้านแถวเท่านั้นและไม่มีรหัสจำนวนมากผูกอยู่กับตารางเหล่านี้คุณก็อาจจะสามารถเริ่มต้นในด้านที่สมบูรณ์แบบมากขึ้น / "บริสุทธิ์" ของสิ่งต่าง ๆ

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


17

ตามที่ Martin Fowler มี 3 วิธีในการแก้ไขปัญหาของการสืบทอดตาราง:

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

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

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


@ เสมอการเรียนรู้ใหม่ฉันคิดว่าคำถามนี้คือการติดตามในdba.stackexchange.com/questions/139092ถูกต้องหรือไม่ ในการดำเนินการมีคุณทำมีมรดกตาราง
Remus Rusanu

ใช่ก่อนถามคำถามนี้ฉันต้องการตรวจสอบให้แน่ใจว่าฉันเข้าใจวิธีการใช้การออกแบบประเภท / ประเภทย่อยให้ถูกต้องก่อน ตอนนี้ผมต้องเผชิญกับปัญหาที่อธิบายไว้ข้างต้นเมื่อบาง ( แต่ไม่ใช่ทั้งหมด) ได้ร่วมกัน subclasses แอตทริบิวต์ ฉันสงสัยว่ามีบางอย่างที่ฉันสามารถทำได้เพื่อเพิ่มประสิทธิภาพตัวแบบข้อมูลในกรณีนั้นแทนที่จะเพิกเฉยต่อความแตกต่างนั้น ...
AlwaysLearningNewStuff

6

ตามการตีความข้อกำหนดของฉันของคุณคุณต้องการค้นหาวิธีในการใช้โครงสร้างsupertype-subtypeสองแบบที่แตกต่างกัน (แต่เชื่อมต่อ )

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

กฎเกณฑ์ทางธุรกิจ

ต่อไปนี้เป็นข้อความบางส่วนที่จะช่วยฉันในการสร้างโมเดลเชิงตรรกะ:

  • A Foo is either one Bar or one C
  • A Foo is categorized by one FooType
  • A Bar is either one A or one C
  • A Bar is classified by one BarType

โมเดลเชิงตรรกะ

จากนั้นแบบจำลองตรรกะIDEF1X [1]จะแสดงในรูปที่ 1 (และคุณสามารถดาวน์โหลดได้จาก Dropbox ในรูปแบบ PDFเช่นกัน):

รูปที่ 1 - โมเดลข้อมูลความสัมพันธ์แบบ Supertype-Subtype

นอกจากนี้ The Foo and Bar

ฉันไม่ได้เพิ่มFooและBarทำให้โมเดลดูดีขึ้น แต่เพื่อให้แสดงออกได้มากขึ้น ฉันคิดว่าพวกเขามีความสำคัญเนื่องจากต่อไปนี้:

  • ในฐานะที่เป็นAและBมีคุณสมบัติที่มีชื่อEคุณสมบัตินี้แสดงให้เห็นว่าพวกเขาเป็นประเภท subentity ของที่แตกต่างกัน ( แต่ที่เกี่ยวข้อง) การเรียงลำดับของแนวคิด , เหตุการณ์ , คน , วัดฯลฯ ซึ่งผมเป็นตัวแทนโดยวิธีการของBarประเภท superentity ว่าในที่สุดก็เป็น ประเภทย่อยของFooซึ่งถือDแอตทริบิวต์ที่ด้านบนของลำดับชั้น

  • เนื่องจากCหุ้นเพียงหนึ่งแอตทริบิวต์กับส่วนที่เหลือของประเภทกิจการภายใต้การอภิปรายซึ่ง ได้แก่Dด้านนี้เอาแต่ใจว่ามันเป็นชนิด subentity ของชนิดของอีกแนวคิด , เหตุการณ์ , คน , วัดฯลฯ ดังนั้นฉันภาพกรณีนี้โดยอาศัยอำนาจตามFooชนิดเอนทิตีซุปเปอร์

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

ปัจจัยสำคัญในระยะการออกแบบ

มันค่อนข้างมีประโยชน์ที่จะต้องตระหนักถึงความจริงที่ว่าการวางคำศัพท์ทั้งหมดไว้ในคลัสเตอร์ supertype-subtype พิเศษนั้นเป็นความสัมพันธ์ปกติ ให้เราอธิบายสถานการณ์ด้วยวิธีต่อไปนี้:

  • แต่ละพิเศษประเภท superentityเกิดขึ้นจะเกี่ยวข้องกับการเพียงหนึ่งsubentity ชนิดสมบูรณ์

ดังนั้นจึงมีการติดต่อ (หรือ cardinality) ของหนึ่งต่อหนึ่ง (1: 1) ในกรณีเหล่านี้

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

โครงสร้างคอนกรีต DDL

และจากนั้นฉันเขียนโครงสร้าง DDL ที่ยึดตามโมเดลเชิงตรรกะที่แสดงด้านบน:

CREATE TABLE FooType -- Look-up table.
(
    FooTypeCode     CHAR(2)  NOT NULL,
    Description     CHAR(90) NOT NULL, 
    CreatedDateTime DATETIME NOT NULL,
    CONSTRAINT PK_FooType             PRIMARY KEY (FooTypeCode),
    CONSTRAINT AK_FooType_Description UNIQUE      (Description)
);

CREATE TABLE Foo -- Supertype
(
    FooId           INT      NOT NULL, -- This PK migrates (1) to ‘Bar’ as ‘BarId’, (2) to ‘A’ as ‘AId’, (3) to ‘B’ as ‘BId’, and (4) to ‘C’ as ‘CId’.
    FooTypeCode     CHAR(2)  NOT NULL, -- Discriminator column.
    D               INT      NOT NULL, -- Column that applies to ‘Bar’ (and therefore to ‘A’ and ‘B’) and ‘C’.
    CreatedDateTime DATETIME NOT NULL,
    CONSTRAINT PK_Foo                 PRIMARY KEY (FooId),
    CONSTRAINT FK_from_Foo_to_FooType FOREIGN KEY (FooTypeCode)
        REFERENCES FooType (FooTypeCode)
);

CREATE TABLE BarType -- Look-up table.
(
    BarTypeCode CHAR(1)  NOT NULL,  
    Description CHAR(90) NOT NULL,  
    CONSTRAINT PK_BarType             PRIMARY KEY (BarTypeCode),
    CONSTRAINT AK_BarType_Description UNIQUE      (Description)
);

CREATE TABLE Bar -- Subtype of ‘Foo’.
(
    BarId       INT     NOT NULL, -- PK and FK.
    BarTypeCode CHAR(1) NOT NULL, -- Discriminator column. 
    E           INT     NOT NULL, -- Column that applies to ‘A’ and ‘B’.
    CONSTRAINT PK_Bar             PRIMARY KEY (BarId),
    CONSTRAINT FK_from_Bar_to_Foo FOREIGN KEY (BarId)
        REFERENCES Foo (FooId),
    CONSTRAINT FK_from_Bar_to_BarType FOREIGN KEY (BarTypeCode)
        REFERENCES BarType (BarTypeCode)    
);

CREATE TABLE A -- Subtype of ‘Bar’.
(
    AId INT NOT NULL, -- PK and FK.
    X   INT NOT NULL, -- Particular column.  
    CONSTRAINT PK_A             PRIMARY KEY (AId),
    CONSTRAINT FK_from_A_to_Bar FOREIGN KEY (AId)
        REFERENCES Bar (BarId)  
);

CREATE TABLE B -- (1) Subtype of ‘Bar’ and (2) supertype of ‘A’ and ‘B’.
(
    BId INT NOT NULL, -- PK and FK.
    Y   INT NOT NULL, -- Particular column.  
    CONSTRAINT PK_B             PRIMARY KEY (BId),
    CONSTRAINT FK_from_B_to_Bar FOREIGN KEY (BId)
        REFERENCES Bar (BarId)  
);

CREATE TABLE C -- Subtype of ‘Foo’.
(
    CId INT NOT NULL, -- PK and FK.
    Z   INT NOT NULL, -- Particular column.  
    CONSTRAINT PK_C             PRIMARY KEY (CId),
    CONSTRAINT FK_from_C_to_Foo FOREIGN KEY (FooId)
        REFERENCES Foo (FooId)  
);

ด้วยโครงสร้างนี้คุณหลีกเลี่ยงการจัดเก็บเครื่องหมาย NULL ในตารางฐานของคุณ (หรือความสัมพันธ์ ) ซึ่งจะแนะนำความคลุมเครือให้กับฐานข้อมูลของคุณ

การพิจารณาความซื่อสัตย์ความสอดคล้องและอื่น ๆ

เมื่อคุณใช้ฐานข้อมูลของคุณคุณต้องตรวจสอบให้แน่ใจว่า (a) แต่ละแถวsupertype พิเศษนั้นได้รับการเติมเต็มด้วยคู่ของsubtype ที่สอดคล้องกันและในทางกลับกันรับประกันได้ว่า (b) แถวย่อยดังกล่าวเข้ากันได้กับค่าที่อยู่ในคอลัมน์discriminator supertype . ดังนั้นจึงค่อนข้างสะดวกในการใช้ ACID TRANSACTIONSเพื่อให้แน่ใจว่าตรงตามเงื่อนไขเหล่านี้ในฐานข้อมูลของคุณ

คุณไม่ควรละทิ้งความแข็งแกร่งเชิงตรรกะการแสดงออกของตนเองและความถูกต้องของฐานข้อมูลของคุณสิ่งเหล่านี้เป็นแง่มุมที่ทำให้ฐานข้อมูลของคุณแข็งแกร่งขึ้น

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

การดึงข้อมูลตามนิยามของ VIEW

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

อย่างที่คุณเห็น“ เทด” Codd เป็นอัจฉริยะอย่างไม่ต้องสงสัย เครื่องมือที่เขาพินัยกรรมค่อนข้างแข็งแกร่งและสง่างามและแน่นอนว่ามีการบูรณาการซึ่งกันและกัน

แหล่งข้อมูลที่เกี่ยวข้อง

หากคุณต้องการวิเคราะห์ฐานข้อมูลที่กว้างขวางซึ่งเกี่ยวข้องกับความสัมพันธ์แบบ supertype-subtype คุณจะพบคุณค่าของคำตอบพิเศษที่เสนอโดย@PerformanceDBAกับคำถาม Stack Overflow ต่อไปนี้:


บันทึก

1. Integration Definition สำหรับการสร้างแบบจำลองข้อมูล ( IDEF1X ) เป็นเทคนิคการสร้างแบบจำลองข้อมูลที่ขอแนะนำอย่างสูงซึ่งก่อตั้งขึ้นเป็นมาตรฐานในเดือนธันวาคม 1993 โดยสถาบันมาตรฐานและเทคโนโลยีแห่งชาติของสหรัฐอเมริกา ( NIST ) มันมีพื้นฐานมาจาก(a)เนื้อหาทางทฤษฎียุคแรกที่เขียนโดย Dr. EF Codd; ใน(ข) Entity-Relationshipมุมมองของข้อมูลที่พัฒนาโดยดร. พีพีเฉิน ; และ(c)เทคนิคการออกแบบฐานข้อมูลแบบลอจิคัลสร้างโดย Robert G. Brown เป็นที่น่าสังเกตว่า IDEF1X ได้รับการทำเป็นทางการโดยใช้ตรรกะลำดับที่หนึ่ง


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