Tôi có nên thêm khóa ngoại liên tục?


11

Ví dụ đơn giản: có một bảng khách hàng.

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

Tất cả các dữ liệu khác trong cơ sở dữ liệu nên liên kết đến a Customer, vì vậy, ví dụ Ordersnhư thế này:

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

Giả sử bây giờ có một bảng liên kết đến 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)
)

Tôi có nên thêm một khóa ngoại riêng biệt từ Itemsđến Customers?

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

Thay vào đó, một hình ảnh: tôi có nên thêm đường nét đứt / FK không?

Lược đồ ví dụ đơn giản


Chỉnh sửa: Tôi đã thêm các định nghĩa khóa chính vào các bảng. Tôi muốn nhắc lại ở điểm tôi đã nêu ở trên: cơ sở dữ liệu về cơ bản bị khách hàng bỏ qua, như một biện pháp chính xác / bảo mật. Do đó, tất cả các khóa chính đều chứa customerID.


2
Không, bạn không nên. Không cần thêm FK. Ràng buộc được thi hành bởi hai FK khác.
ypercubeᵀᴹ

@ypercube Có bất kỳ hình phạt hiệu suất nào khi có FK dư thừa không? Bất kỳ lợi thế nào bạn có thể nghĩ đến? ...
vektor

1
@vektor, các khía cạnh hiệu suất có thể thay đổi từ một rdbms khác, nhưng nhìn chung, bạn có tác động hiệu suất cho mỗi FK mới mà bạn thêm, bởi vì mọi thao tác chèn / cập nhật / xóa trong một trong các bảng PK / FK phải được kiểm tra hạn chế. Với các bảng PK lớn, hình phạt hiệu suất này có thể khá nghiêm trọng.
Daniel Hutmacher

Câu trả lời:


6

Tôi nghĩ rằng đây là ý tưởng ban đầu.

nhập mô tả hình ảnh ở đây

Điều đầu tiên cần lưu ý là PK trên bảng LineItem có ba thuộc tính {CustomerID, CustomerOrderNo, OdrerItemNo}, trái ngược với chỉ hai trong ví dụ của bạn.

Điều thứ hai cần lưu ý là sự nhầm lẫn do việc sử dụng idtên chung cho một thuộc tính.

CustomerOrderNotưởng nhất phải là (1,2,3 ..) cho mỗi khách hàng và OrderItemNo(1,2,3 ...) cho mỗi đơn hàng.

Chà, điều này thật tuyệt nếu có thể, nhưng yêu cầu một truy vấn tìm kiếm giá trị tối đa trước đó, như

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

thường không được ưa thích trong môi trường có khối lượng giao dịch cao, vì vậy người ta thường thấy những thứ này được thay thế bằng mức tăng tự động, về cơ bản phục vụ cùng một mục đích. Đúng là tính năng tăng tự động này hiện là duy nhất, do đó nó có thể được sử dụng làm KHÓA - nhưng bạn có thể chọn xem nó như một sự thỏa hiệp cần thiết cho OrderItemNo.

Vì vậy, với một số đổi tên CustomerOrderNo -> OrderNoOrderItemNo-> ItemNobạn có thể đến mô hình này

nhập mô tả hình ảnh ở đây

Vì vậy, bây giờ nếu bạn nhìn vào Ordersau đây là duy nhất

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

Lưu ý rằng {CustomerID, OrderNo}được truyền đến LineItemđể phục vụ như một FK.

Nếu bạn nheo mắt một chút, điều này gần với ví dụ của bạn, nhưng PKs {ItemNo} and {OrderNo}chỉ với - trái ngược với hai PK cột từ ví dụ của bạn.

Bây giờ câu hỏi là, tại sao không đơn giản hóa để một cái gì đó như thế này?

nhập mô tả hình ảnh ở đây

Đó là tốt, nhưng đưa ra PATH sự phụ thuộc - bạn không thể tham gia LineItemvới Customertrực tiếp, phải sử dụng Ordertrong tham gia.


Tôi thích trường hợp đầu tiên khi có thể - bạn chọn yêu thích của bạn. Và rõ ràng, không có nhu cầu về FK trực tiếp từ LineItemđể Customertrong ba trường hợp.


Tôi đã tìm kiếm xung quanh, nhưng tôi không thể thấy "sự phụ thuộc đường dẫn" được sử dụng như một thuật ngữ được áp dụng rộng rãi cho cái mà tôi sẽ gọi là "mối quan hệ bắc cầu cấp độ 2" (mặc dù thuật ngữ của tôi có lẽ cũng không chính xác)
Dai

2

"Mặt hàng" không nên tham chiếu trực tiếp đến "khách hàng", bởi vì điều này được ngụ ý bởi "đơn đặt hàng" của mặt hàng đó. Vì vậy, bạn sẽ không cần các cột "khách hàng" trên bảng "mặt hàng".

Mối quan hệ của mặt hàng với khách hàng được đảm bảo với khóa ngoại hiện có.

Nếu order.id là một cột danh tính, hãy xem xét loại bỏ các mặt hàng. Khách hàng hoàn toàn.


1
Cảm ơn, tôi đã không nhận thấy rằng "khách hàng" cũng được bao gồm trong FK đầu tiên từ "mặt hàng" đến "đơn hàng". Tôi đã xây dựng câu trả lời của tôi cho phù hợp.
Daniel Hutmacher

@DanielHutmacher Tôi đã chỉnh sửa câu hỏi để chứa các khóa chính của bảng. Điều này giải thích các FK kỳ lạ mà bạn đề cập trong bản chỉnh sửa của mình.
vektor

Ok, tôi đã cập nhật câu trả lời của mình. :)
Daniel Hutmacher

Tôi đoán rằng việc có customertrong tất cả các bảng (và do đó làm im lặng DB) là một cách tiếp cận khác thường. Tôi phải thú nhận rằng đó chỉ là thứ tôi đã thấy trong tác phẩm trước đây của mình. Nó có ý nghĩa gì với bạn không? Bạn đã thấy một thiết kế như vậy trước đây?
vektor

Tôi muốn nói rằng nó trông giống như một cách tiếp cận cơ sở dữ liệu (lược đồ sao), nơi bạn muốn cố tình làm chuẩn hóa dữ liệu để loại bỏ các phép nối. Hoặc khóa chính có thể là hợp số, tức là đơn hàng thứ nhất, thứ hai, thứ ba, thứ tự thứ nhất, thứ hai của khách hàng B, v.v. - khi chỉ riêng cột id đơn hàng không phải là duy nhất.
Daniel Hutmacher
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.