รูปแบบการออกแบบ - หนึ่งในหลายตารางหลัก


13

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

contrived ตัวอย่าง
ของ Let Alertsบอกว่าระบบของฉันมี สามารถรับการแจ้งเตือนสำหรับวัตถุที่หลากหลาย - ลูกค้าข่าวสารและผลิตภัณฑ์ การแจ้งเตือนที่กำหนดสามารถเป็นแบบหนึ่งเดียวเท่านั้น ไม่ว่าจะด้วยเหตุผลใดก็ตามลูกค้าบทความและผลิตภัณฑ์กำลังเคลื่อนไหวอย่างรวดเร็ว (หรือแปลเป็นภาษาท้องถิ่น) ดังนั้นจึงไม่สามารถดึงข้อความ / ข้อมูลที่จำเป็นลงใน Alerts เมื่อสร้างการแจ้งเตือน ด้วยการตั้งค่านี้ฉันได้เห็นสองวิธี

หมายเหตุ: ด้านล่าง DDL สำหรับ SQL Server แต่คำถามของฉันควรใช้กับ DBMS ใด ๆ

โซลูชันที่ 1 - FKeys เป็นค่า Nullable หลายตัว

ในโซลูชันนี้ตารางที่เชื่อมโยงไปยังตารางหนึ่งในหลายแห่งมีคอลัมน์ FK หลายแห่ง (เพื่อความกะทัดรัดสั้น DDL ด้านล่างจะไม่แสดงการสร้าง FK) THE GOOD - ในวิธีนี้มันดีที่ฉันมีกุญแจต่างประเทศ null-optinality ของ FK ทำให้สะดวกและง่ายในการเพิ่มข้อมูลที่แม่นยำ การค้นหาข้อความที่ไม่ดีเพราะต้องใช้คำสั่งN LEFT JOINS หรือN UNION เพื่อรับข้อมูลที่เกี่ยวข้อง ใน SQL Server เฉพาะ LEFT JOINS ยับยั้งการสร้างมุมมองที่จัดทำดัชนีไว้

CREATE TABLE Product (
    ProductID    int identity(1,1) not null,
    CreateUTC    datetime2(7) not null,
     Name        varchar(100) not null
    CONSTRAINT   PK_Product Primary Key CLUSTERED (ProductID)
)
CREATE TABLE Customer (
    CustomerID  int identity(1,1) not null,
    CreateUTC   datetime2(7) not null,
     Name       varchar(100) not null
    CONSTRAINT  PK_Customer Primary Key CLUSTERED (CustomerID)
)
CREATE TABLE News (
    NewsID      int identity(1,1) not null,
    CreateUTC   datetime2(7) not null,
    Name        varchar(100) not null
    CONSTRAINT  PK_News Primary Key CLUSTERED (NewsID)
)

CREATE TABLE Alert (
    AlertID     int identity(1,1) not null,
    CreateUTC   datetime2(7) not null,
    ProductID   int null,
    NewsID      int null,
    CustomerID  int null,
    CONSTRAINT  PK_Alert Primary Key CLUSTERED (AlertID)
)

ALTER TABLE Alert WITH CHECK ADD CONSTRAINT CK_OnlyOneFKAllowed 
CHECK ( 
    (ProductID is not null AND NewsID is     null and CustomerID is     null) OR 
    (ProductID is     null AND NewsID is not null and CustomerID is     null) OR 
    (ProductID is     null AND NewsID is     null and CustomerID is not null) 
)

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

CREATE TABLE Product (
    ProductID    int identity(1,1) not null,
    CreateUTC    datetime2(7) not null,
     Name        varchar(100) not null
    AlertID     int null,
    CONSTRAINT   PK_Product Primary Key CLUSTERED (ProductID)
)
CREATE TABLE Customer (
    CustomerID  int identity(1,1) not null,
    CreateUTC   datetime2(7) not null,
     Name       varchar(100) not null
    AlertID     int null,
    CONSTRAINT  PK_Customer Primary Key CLUSTERED (CustomerID)
)
CREATE TABLE News (
    NewsID      int identity(1,1) not null,
    CreateUTC   datetime2(7) not null,
    Name        varchar(100) not null
    AlertID     int null,
    CONSTRAINT  PK_News Primary Key CLUSTERED (NewsID)
)

CREATE TABLE Alert (
    AlertID     int identity(1,1) not null,
    CreateUTC   datetime2(7) not null,
    CONSTRAINT  PK_Alert Primary Key CLUSTERED (AlertID)
)

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


1
คุณสามารถสร้างหนึ่งตารางหลัก Alertable โดยมีคอลัมน์ต่อไปนี้: ID, CreateDate, ชื่อ, ประเภท คุณสามารถให้ตารางลูกสามลูกของคุณไปที่ FK ได้และ ALert ของคุณจะเป็น FK เพียงหนึ่งโต๊ะซึ่งสามารถเตือนได้
AK

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

1
@EBarr: "ถ้าฉันต้องส่ง 'ชื่อ' ในภาษาของผู้ใช้ฉันไม่สามารถเก็บมันไว้ใน Alertable นั่นมันสมเหตุสมผลไหม?" ไม่เลย ด้วยสคีมาปัจจุบันของคุณหากคุณต้องส่ง 'ชื่อ' ในภาษาของผู้ใช้คุณสามารถเก็บไว้ในตารางผลิตภัณฑ์ลูกค้าหรือข่าวได้หรือไม่
ypercubeᵀᴹ

@ypercube ฉันเพิ่มว่าแต่ละตารางเหล่านั้นมีตารางภาษาที่เกี่ยวข้อง ฉันพยายามสร้างสถานการณ์ที่ข้อความ "ชื่อ" อาจแตกต่างกันไปตามคำขอและไม่สามารถจัดเก็บใน Alertable ได้
EBarr

ฉันขอเสนอคำว่า "การเข้าร่วมปลาหมึก" สำหรับคำค้นหาที่คุณต้องทำเพื่อดูการแจ้งเตือนทั้งหมดและผู้ปกครองที่เกี่ยวข้อง :)
นาธานลอง

คำตอบ:


4

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

คุณติดอยู่กับโซลูชันเพียงสองตัวเนื่องจากการปฏิบัติตามข้อกำหนด 3NF ที่เข้มงวด

ฉันจะออกแบบ schema การแต่งงานที่น้อยกว่า:

CREATE TABLE Product  (ProductID  int identity(1,1) not null, ...)
CREATE TABLE Customer (CustomerID int identity(1,1) not null, ...)
CREATE TABLE News     (NewsID     int identity(1,1) not null, ...)

CREATE TABLE Alert (
  -- See (1)
  -- AlertID     int identity(1,1) not null,

  AlertClass char(1) not null, -- 'P' - Product, 'C' - Customer, 'N' - News
  ForeignKey int not null,
  CreateUTC  datetime2(7) not null,

  -- See (2)
  CONSTRAINT  PK_Alert Primary Key CLUSTERED (AlertClass, ForeignKey)
)

-- (1) you don't need to specify an ID 'just because'. If it's meaningless, just don't.
-- (2) I do believe in composite keys

หรือหากจำเป็นต้องมีความสัมพันธ์ที่สมบูรณ์ฉันอาจออกแบบ:

CREATE TABLE Product  (ProductID  int identity(1,1) not null, ...)
CREATE TABLE Customer (CustomerID int identity(1,1) not null, ...)
CREATE TABLE News     (NewsID     int identity(1,1) not null, ...)

CREATE TABLE Alert (
  AlertID     int identity(1,1) not null,
  AlertClass char(1) not null, /* 'P' - Product, 'C' - Customer, 'N' - News */
  CreateUTC  datetime2(7) not null,
  CONSTRAINT  PK_Alert Primary Key CLUSTERED (AlertID)
)

CREATE TABLE AlertProduct  (AlertID..., ProductID...,  CONSTRAINT FK_AlertProduct_X_Product(ProductID)    REFERENCES Product)
CREATE TABLE AlertCustomer (AlertID..., CustomerID..., CONSTRAINT FK_AlertCustomer_X_Customer(CustomerID) REFERENCES Customer)
CREATE TABLE AlertNews     (AlertID..., NewsID...,     CONSTRAINT FK_AlertNews_X_News(NewsID)             REFERENCES News)

อย่างไรก็ตาม...

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

สิ่งเหล่านี้นำเสนอสิ่งที่มีคุณธรรม?

พวกเขาต่างกันอย่างละเอียดและมีน้ำหนักเท่ากันในเกณฑ์:

  • ประสิทธิภาพของการแทรกและการอัพเดต
  • ความซับซ้อนในการสอบถาม
  • พื้นที่เก็บข้อมูล

ดังนั้นเลือกสิ่งที่ดีกว่าสำหรับคุณ


1
ขอบคุณสำหรับอินพุต; ฉันเห็นด้วยกับความคิดเห็นส่วนใหญ่ของคุณ ฉันอาจอธิบายความสัมพันธ์ที่ต้องการ (ไม่รวมโซลูชันที่ 2 ในสายตาของคุณ) ด้วยความตั้งใจเพราะมันเป็นตัวอย่างที่ทำขึ้นมา fn1 - เข้าใจแล้วฉันแค่ทำให้ตารางง่ายขึ้นเพื่อมุ่งเน้นไปที่ปัญหา fn2 - แป้นคอมโพสิตและฉันย้อนกลับไป! Re schema coupling ที่น้อยกว่าฉันเข้าใจความเรียบง่าย แต่ส่วนตัวพยายามออกแบบด้วย DRI ทุกที่ที่เป็นไปได้
EBarr

จากการตรวจสอบนี้ฉันเริ่มสงสัยความถูกต้องของวิธีการแก้ปัญหาของฉัน ... อย่างไรก็ตามมันได้รับการโหวตสองครั้งซึ่งฉันขอบคุณ แม้ว่าฉันเชื่อว่าการออกแบบของฉันใช้ได้ แต่ไม่เหมาะสำหรับปัญหาที่กำหนดเนื่องจากสหภาพแรงงาน / ตัวเชื่อม 'n' ไม่ได้รับการแก้ไข ...
Marcus Vinicius Pompeu

ตัวย่อ DRI ทำให้ฉันได้ สำหรับคุณทั้งหมดมันหมายถึง Declarative Referential Integrity เทคนิคที่อยู่เบื้องหลัง Referential Data integrity ซึ่งโดยทั่วไปจะถูกนำไปใช้เป็น ... (drum roll) ... DDL FOREIGN KEY statement ข้อมูลเพิ่มเติมเกี่ยวกับen.wikipedia.org/wiki/Declarative_Referential_Integrityและmsdn.microsoft.com/en-us/library/…
Marcus Vinicius Pompeu

1

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

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