การออกแบบฐานข้อมูล: การทำให้ความสัมพันธ์แบบ“ (หลายต่อหลายคน) เป็นแบบปกติ” ให้เป็นมาตรฐาน


14

เวอร์ชั่นสั้น

ฉันต้องเพิ่มคุณสมบัติเพิ่มเติมจำนวนคงที่ให้กับแต่ละคู่ในการเข้าร่วมหลายต่อหลายที่มีอยู่ การข้ามไปยังไดอะแกรมด้านล่างตัวเลือกที่ 1-4 เป็นวิธีที่ดีที่สุดในแง่ของข้อดีและข้อเสียเพื่อให้บรรลุเป้าหมายนี้โดยการขยาย Base Case? หรือมีทางเลือกอื่นที่ดีกว่าที่ฉันไม่ได้พิจารณาที่นี่?

รุ่นอีกต่อไป

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

  1. คู่หนึ่งคู่เชื่อมโยงกับคุณสมบัติเพิ่มเติมจำนวนหนึ่งชุด
  2. หนึ่งคู่เชื่อมโยงกับคุณสมบัติเพิ่มเติมมากมาย
  3. วัตถุ (สอง) หลายตัวเชื่อมโยงกับคุณสมบัติหนึ่งชุด
  4. วัตถุจำนวนมากเชื่อมโยงกับคุณสมบัติมากมาย

ตัวอย่าง

ฉันมีประเภทของวัตถุสองชนิดคือ X และ Y แต่ละชนิดมี ID ที่ไม่ซ้ำกันและตารางการเชื่อมโยงที่objx_objyมีคอลัมน์x_idและy_idซึ่งรวมกันเป็นคีย์หลักสำหรับลิงก์ แต่ละ X สามารถเกี่ยวข้องกับ Ys ได้หลายคนและในทางกลับกัน นี่คือการตั้งค่าสำหรับความสัมพันธ์แบบหลายต่อหลายที่มีอยู่ของฉัน

เคสฐาน

เคสฐาน

ตอนนี้นอกจากนี้ฉันมีชุดของคุณสมบัติที่กำหนดไว้ในตารางอื่นและชุดของเงื่อนไขที่คู่ (X, Y) ที่กำหนดควรมีคุณสมบัติ P จำนวนเงื่อนไขได้รับการแก้ไขและเหมือนกันสำหรับทุกคู่ พวกเขาพูดว่า "ในสถานการณ์ C1 คู่ (X1, Y1) มีคุณสมบัติ P1", "ในสถานการณ์ C2, คู่ (X1, Y1) มีคุณสมบัติ P2" และต่อไปสำหรับสามสถานการณ์ / เงื่อนไขสำหรับแต่ละคู่ในการเข้าร่วม โต๊ะ.

ตัวเลือกที่ 1

ในสถานการณ์ปัจจุบันของฉันมีตรงสามเงื่อนไขดังกล่าวและฉันมีเหตุผลที่จะคาดหวังว่าจะเพิ่มขึ้นไม่ดังนั้นความเป็นไปได้คือการเพิ่มคอลัมน์c1_p_id, c2_p_idและc3_p_idการfeatx_featyระบุหาได้รับx_idและy_idซึ่งอสังหาริมทรัพย์p_idเพื่อการใช้งานในแต่ละแห่งที่สามกรณี .

ตัวเลือกที่ 1

ดูเหมือนจะไม่เป็นความคิดที่ดีสำหรับฉันเพราะมันทำให้ SQL ซับซ้อนเพื่อเลือกคุณสมบัติทั้งหมดที่ใช้กับคุณลักษณะและไม่ได้ปรับขนาดตามเงื่อนไขเพิ่มเติม อย่างไรก็ตามจะบังคับใช้ข้อกำหนดของเงื่อนไขจำนวนหนึ่งต่อคู่ (X, Y) ในความเป็นจริงมันเป็นตัวเลือกเดียวที่นี่ที่ทำเช่นนั้น

ตัวเลือก 2

สร้างตารางเงื่อนไขcondและเพิ่มรหัสเงื่อนไขลงในคีย์หลักของตารางเข้าร่วม

ตัวเลือก 2

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

SELECT objx.*, objy.* FROM objx
  INNER JOIN objx_objy ON objx_objy.x_id = objx.id
  INNER JOIN objy ON objy.id = objx_objy.y_id

ฉันต้องเพิ่มส่วนDISTINCTคำสั่งเพื่อหลีกเลี่ยงรายการที่ซ้ำกัน ดูเหมือนว่าจะสูญเสียความจริงที่ว่าแต่ละคู่ควรมีอยู่เพียงครั้งเดียว

ตัวเลือก 3

สร้าง 'รหัสประจำตัวคู่' ใหม่ในตารางเข้าร่วมแล้วมีตารางลิงก์ที่สองระหว่างตารางแรกและคุณสมบัติและเงื่อนไข

ตัวเลือก 3

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

ตัวเลือก 4 (3b)

โดยพื้นฐานแล้วเหมือนกับตัวเลือก 3 แต่ไม่มีการสร้างฟิลด์ ID เพิ่มเติม นี้สามารถทำได้โดยการใส่รหัสเดิมทั้งในตารางใหม่เข้าร่วมเพื่อให้มันมีx_idและเขตแทนy_idxy_id

ตัวเลือก 4

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

สรุป

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

เป็นหนึ่งในตัวเลือกเหล่านี้เป็นวิธีที่ดีที่สุดของฉันไปข้างหน้าหรือมีโครงสร้างอื่นที่ฉันควรพิจารณา?


โดยรวมแล้ว 1 และ 4 ดูเหมือนตัวเลือกที่ดีที่สุดฉันเห็นด้วย คงไม่ใช่เรื่องง่ายที่จะบังคับใช้คุณสมบัติจำนวนคงที่ (3) กับตัวเลือก 4 แต่ฉันคิดว่ามันเป็นไปได้
ypercubeᵀᴹ

สำหรับDISTINCTประโยคที่ฉันคิดของแบบสอบถามเช่นหนึ่งในตอนท้ายของ # 2 ซึ่งเชื่อมโยงxและyผ่านxycแต่ไม่ได้อ้างถึงc... ดังนั้นถ้าฉันมี(x_id, y_id, c_id)ข้อ จำกัดUNIQUEกับแถว(1,1,1)และ(1,1,2)จากนั้นSELECT x.id, y.id FROM x JOIN xyc JOIN yฉันจะได้รับสองเหมือนกัน แถว(1,1), และ(1,1).
Michael Underwood

1
อาโอเค. ฉันจะยกเลิกตัวเลือก 2 ต่อไป ฉันจะไปกับ 1 หรือ 4
ypercubeᵀᴹ

ยิ่งฉันคิดถึงมันมากเท่าไหร่ฉันยิ่งรู้สึกว่าการ จำกัด จำนวนของคุณสมบัติให้เป็นสามเท่านั้นเป็นสิ่งที่สำคัญที่สุดสำหรับความต้องการของฉัน ดังนั้นหากไม่ได้รับข้อเสนอแนะที่สร้างสรรค์เพิ่มเติมในอีกสักครู่ฉันอาจจะไป # 4 ในตอนนี้ ขอบคุณสำหรับการป้อนข้อมูลของคุณ @ypercube!
Michael Underwood

คำตอบ:


7
  • ตัวเลือกที่ 1

    * สิ่งนี้ดูเหมือนจะไม่เป็นความคิดที่ดีสำหรับฉันเพราะมันทำให้ SQL ยุ่งยากในการเลือกคุณสมบัติทั้งหมดที่ใช้กับคุณลักษณะ ...

    มันไม่จำเป็นต้องซับซ้อนแบบสอบถาม SQL (ดูข้อสรุปด้านล่าง)

    …และไม่พร้อมที่จะปรับเงื่อนไขให้มากขึ้น ...

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

    อย่างไรก็ตามจะบังคับใช้ข้อกำหนดของเงื่อนไขจำนวนหนึ่งต่อคู่ (X, Y) ในความเป็นจริงมันเป็นตัวเลือกเดียวที่นี่ที่ทำเช่นนั้น *

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

  • ตัวเลือก 2

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

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

  • ตัวเลือก 3

    มันสมเหตุสมผลหรือไม่ที่จะสร้าง ID ใหม่ที่ระบุอะไรอื่นนอกจาก ID ที่มีอยู่

    ไม่ไม่ - ตัวเลือก 4 ดีกว่าในทุก ๆ ด้าน

  • ตัวเลือก 4

    …โดยทั่วไปจะทำซ้ำทั้งตารางหลายครั้ง (หรือรู้สึกอย่างนั้น) ดังนั้นจึงไม่เหมาะ

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

ข้อสรุป

การตั้งค่าของฉันจะเป็นตัวเลือกที่ 1 หากจำนวนคุณสมบัติต่อobjx_objyมีแนวโน้มที่จะมีเสถียรภาพและหากคุณไม่สามารถจินตนาการได้ว่าจะมีการเพิ่มมากกว่าหนึ่งรายการ นอกจากนี้ยังเป็นตัวเลือกเดียวที่บังคับใช้ข้อ จำกัด 'จำนวนคุณสมบัติ = 3' - การบังคับใช้ข้อ จำกัด ที่คล้ายกันในตัวเลือก 4 น่าจะเกี่ยวข้องกับการเพิ่มc1_p_id... คอลัมน์ในตาราง xy ต่อไป *

หากคุณไม่สนใจสภาพนั้นมากนักและคุณก็มีเหตุผลที่ต้องสงสัยว่าจำนวนของสภาพอสังหาริมทรัพย์จะมีเสถียรภาพแล้วให้เลือกตัวเลือก 4

หากคุณไม่แน่ใจว่าตัวเลือกใดให้เลือก 1 - ง่ายกว่าและดีกว่าถ้าคุณมีตัวเลือกตามที่คนอื่น ๆ พูด หากคุณถูกเลื่อนออกจากตัวเลือก 1 "... เพราะมันทำให้ SQL ยุ่งยากในการเลือกคุณสมบัติทั้งหมดที่ใช้กับคุณสมบัติ ... " ฉันขอแนะนำให้สร้างมุมมองเพื่อให้ข้อมูลเดียวกับตารางเสริมในตัวเลือก 4:

ตัวเลือก 1 ตาราง:

create table prop(id integer primary key);
create table objx(id integer primary key);
create table objy(id integer primary key);

create table objx_objy(
  x_id integer references objx
, y_id integer references objy
, c1_p_id integer not null references prop
, c2_p_id integer not null references prop
, c3_p_id integer not null references prop
, primary key (x_id, y_id)
);

insert into prop(id) select generate_series(90,99);
insert into objx(id) select generate_series(10,12);
insert into objy(id) select generate_series(20,22);

insert into objx_objy(x_id,y_id,c1_p_id,c2_p_id,c3_p_id)
select objx.id, objy.id, 90, 91, 90+floor(random()*10)
from objx cross join objy;

ดูตัวเลือก 'จำลอง' 4:

create view objx_objy_prop as
select x_id
     , y_id
     , unnest(array[1,2,3]) c_id
     , unnest(array[c1_p_id,c2_p_id,c3_p_id]) p_id
from objx_objy;

"เลือกคุณสมบัติทั้งหมดที่ใช้กับสถานที่":

select distinct p_id from objx_objy_prop where x_id=10 order by p_id;

/*
|p_id|
|---:|
|  90|
|  91|
|  97|
|  98|
*/

dbfiddle ที่นี่


-3

ฉันเชื่อว่าตัวเลือกเหล่านี้สามารถใช้งานได้ แต่ฉันจะไปกับตัวเลือกที่ 1 หากจำนวนของเงื่อนไขได้รับการแก้ไขอย่างแท้จริงที่ 3 และตัวเลือกที่ 2 หากไม่เป็นเช่นนั้น มีดโกนของ Occam ยังใช้งานได้กับการออกแบบฐานข้อมูลปัจจัยอื่น ๆ ทั้งหมดที่เท่ากันกับการออกแบบที่ง่ายที่สุดมักจะดีที่สุด

แม้ว่าหากคุณต้องการปฏิบัติตามกฎการทำให้เป็นมาตรฐานของฐานข้อมูลอย่างเข้มงวด แต่ฉันเชื่อว่าคุณจะต้องไปกับ 2 โดยไม่คำนึงว่าจำนวนของเงื่อนไขได้รับการแก้ไขแล้วหรือไม่

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