ฉันควรเพิ่มคีย์ต่างประเทศสกรรมกริยาหรือไม่


11

ตัวอย่างง่ายๆ: มีตารางลูกค้า

create table Customers (
  id integer,
  constraint CustomersPK primary key (id)
)

ข้อมูลอื่น ๆ ทั้งหมดในฐานข้อมูลควรเชื่อมโยงไปยัง a Customerดังนั้นเช่นOrdersจะมีลักษณะดังนี้:

create table Orders (
  id integer,
  customer integer,
  constraint OrdersPK primary key (customer, id),
  constraint OrdersFKCustomers foreign key (customer) references Customers (id)
)

สมมติว่าตอนนี้มีตารางเชื่อมโยงไปยังOrders:

create table Items (
  id integer,
  customer integer,
  order integer,
  constraint ItemsPK primary key (customer, id),
  constraint ItemsFKOrders foreign key (customer, order) references Orders (customer, id)
)

ฉันควรจะเพิ่มรหัสต่างประเทศแยกต่างหากจากItemsในCustomersหรือไม่

...
constraint ItemsFKCustomers foreign key (customer) references Customers (id)

รูปภาพแทน: ฉันควรจะเพิ่มเส้นประ / FK หรือไม่?

สคีมาตัวอย่างอย่างง่าย


แก้ไข:ฉันได้เพิ่มคำจำกัดความของคีย์หลักในตาราง ฉันต้องการซ้ำอีกครั้งในจุดที่ฉันทำไว้ข้างต้น: ฐานข้อมูลนั้นถูกปิดกั้นโดยลูกค้าโดยทั่วไปเป็นมาตรการความถูกต้อง / ความปลอดภัย ดังนั้นคีย์หลักทั้งหมดมีcustomerID


2
ไม่คุณไม่ควรทำ ไม่จำเป็นต้องมี FK เพิ่มเติม ข้อ จำกัด ถูกบังคับใช้โดย FK อีกสองรายการ
ypercubeᵀᴹ

@ypercube มีบทลงโทษเกี่ยวกับประสิทธิภาพหรือไม่สำหรับการมี FK ซ้ำซ้อนหรือไม่ คุณสามารถนึกถึงข้อดีใด ๆ ...
vektor

1
@vektor ด้านประสิทธิภาพอาจแตกต่างจาก rdbms หนึ่งไปยังอีก แต่โดยทั่วไปคุณจะได้รับผลกระทบต่อประสิทธิภาพสำหรับ FK ใหม่แต่ละครั้งที่คุณเพิ่มเพราะทุก ๆ แทรก / ปรับปรุง / ลบในตาราง PK / FK หนึ่งจะต้องตรวจสอบกับ การ จำกัด ด้วยตาราง PK ขนาดใหญ่การปรับประสิทธิภาพนี้ค่อนข้างรุนแรง
Daniel Hutmacher

คำตอบ:


6

ฉันคิดว่านี่เป็นความคิดดั้งเดิม

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

สิ่งแรกที่ควรสังเกตคือ PK ในตาราง LineItem มีคุณลักษณะสามอย่าง{CustomerID, CustomerOrderNo, OdrerItemNo}ซึ่งตรงข้ามกับสองตัวอย่างในตัวอย่างของคุณ

สิ่งที่สองที่ควรทราบคือความสับสนที่เกิดจากการใช้idชื่อสามัญสำหรับแอตทริบิวต์

ที่CustomerOrderNoควรจะเป็น (1,2,3 .. ) สำหรับลูกค้าแต่ละรายและOrderItemNo(1,2,3 ... ) สำหรับการสั่งซื้อแต่ละครั้ง

นี่เป็นสิ่งที่ดีถ้าเป็นไปได้ แต่ต้องใช้แบบสอบถามเพื่อค้นหาค่าสูงสุดก่อนหน้าเช่น

select max(CustomerOrderNo)
from Order 
where CustomerID = specific_customer ; 

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

ดังนั้นด้วยการเปลี่ยนชื่อCustomerOrderNo -> OrderNoและOrderItemNo-> ItemNoคุณอาจมาถึงรุ่นนี้

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

ดังนั้นตอนนี้ถ้าคุณดูที่Orderต่อไปนี้จะไม่ซ้ำกัน

{OrderNo}             -- PK
{CustomerID, OrderNo} -- superkey,  AK on the diagram.

โปรดทราบว่า{CustomerID, OrderNo}จะแพร่กระจายไปยังLineItemเพื่อทำหน้าที่เป็น FK

หากคุณเหลื่อมกันนิดหน่อยนี่ก็ใกล้เคียงกับตัวอย่างของคุณ แต่มีPKs {ItemNo} and {OrderNo}เพียง - ตรงข้ามกับ PKs สองคอลัมน์จากตัวอย่างของคุณ

ตอนนี้คำถามคือทำไมไม่ลดความซับซ้อนของสิ่งนี้ลง

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

ซึ่งเป็นได้ แต่แนะนำเส้นทางผู้ติด - คุณไม่สามารถเข้าร่วมLineItemด้วยCustomerโดยตรงจะต้องใช้Orderในการเข้าร่วม


ฉันชอบกรณีแรกเมื่อเป็นไปได้ - คุณเลือกรายการโปรดของคุณ และเห็นได้ชัดว่าไม่มีความจำเป็นสำหรับ FK โดยตรงจากLineItemไปCustomerในทั้งสามกรณี


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

2

"รายการ" ไม่ควรอ้างอิงถึง "ลูกค้า" โดยตรงเนื่องจากเป็นนัยโดยคำสั่ง "รายการ" ของรายการ ดังนั้นคุณไม่จำเป็นต้องมีคอลัมน์ "ลูกค้า" ในตาราง "รายการ" เลย

ความสัมพันธ์ของรายการกับลูกค้าจะมั่นใจได้ว่ามีกุญแจต่างประเทศที่มีอยู่

หาก orders.id เป็นคอลัมน์ข้อมูลประจำตัวให้ลองลบ items.customer ทั้งหมด


1
ขอบคุณฉันไม่ได้สังเกตว่า "ลูกค้า" รวมอยู่ใน FK แรกจาก "รายการ" ถึง "คำสั่งซื้อ" ฉันได้อธิบายคำตอบของฉันอย่างละเอียด
Daniel Hutmacher

@DanielHutmacher ฉันได้แก้ไขคำถามเพื่อให้มีคีย์หลักของตารางของฉัน นี่อธิบาย FK แปลก ๆ ที่คุณพูดถึงในการแก้ไขของคุณ
vektor

ตกลงฉันได้อัปเดตคำตอบแล้ว :)
Daniel Hutmacher

ฉันเดาว่าการมีcustomerตารางทั้งหมด (และทำให้ไซโลฐานข้อมูล) เป็นวิธีที่ผิดปกติ ฉันต้องยอมรับว่ามันเป็นเพียงสิ่งที่ฉันเห็นในงานก่อนหน้านี้ของฉัน มันสมเหตุสมผลกับคุณไหม? คุณเคยเห็นการออกแบบดังกล่าวมาก่อนหรือไม่?
vektor

ฉันจะบอกว่าดูเหมือนว่าวิธีการจัดเก็บข้อมูล (รูปแบบสตาร์) ซึ่งคุณต้องการลบข้อมูลให้เป็นปกติเพื่อกำจัดการเข้าร่วม หรือคีย์หลักอาจรวมกันนั่นคือลูกค้า A ลำดับที่หนึ่งที่สองลำดับที่สามที่หนึ่งลูกค้า B ที่หนึ่งลำดับที่สองและอื่น ๆ - เมื่อคอลัมน์รหัสคำสั่งซื้อเพียงอย่างเดียวไม่เหมือนกัน
Daniel Hutmacher
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.