Nhược điểm của việc sử dụng khóa ngoại không thể thay vì tạo bảng giao nhau


15

Nói rằng tôi có sơ đồ ER sau:

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

Bây giờ nếu tôi đại diện cho mối quan hệ sử dụng một chìa khóa nước ngoài của Schooltrong Student, tôi có thể có NULLgiá trị (vì Student không cần phải thuộc về một School), ví dụ:

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

Vì vậy, cách chính xác (dựa trên những gì tôi đã đọc) là tạo một bảng giao nhau để thể hiện mối quan hệ, ví dụ:

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

Bằng cách này, không có NULLgiá trị có thể được trình bày trong bảng School_has_Student.

Nhưng những nhược điểm của việc sử dụng khóa ngoại không thể thay vì tạo bảng giao nhau là gì?


Biên tập:

Tôi đã chọn nhầm ( school_id, student_id) làm khóa chính cho School_has_Studentbảng, điều này làm cho mối quan hệ nhiều-nhiều. Khóa chính đúng phải là student_id:

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


7
Không có cách "chính xác". Có cách tốt nhất cho nhu cầu của bạn.
MetaFight

1
Tôi đồng ý với Doc về tiền đề sai, nhưng có lẽ nó vẫn đủ rõ ràng để trả lời?
MetaFight

Có một tiền đề sai, nhưng nó đủ dễ để nói thẳng ra và giải thích sự khác biệt.

Tôi đã rút lại phiếu bầu gần của mình, nhưng câu "Vì vậy, cách chính xác (dựa trên những gì tôi đã đọc) là tạo một bảng giao nhau để thể hiện mối quan hệ" cho tôi ấn tượng bạn nên cho chúng tôi biết nguồn căng thẳng nào nói với bạn đây là " đúng cách Trong mọi cuốn sách văn bản tôi đã đọc trước đây, cách chính tắc cho các mối quan hệ 1: n là một khóa ngoại duy nhất. Hay bạn đã hiểu nhầm điều gì?
Doc Brown

@Doc Brown Tôi không nhớ mình đã đọc nó ở đâu, nhưng tôi chắc chắn rằng nó nói rằng một bảng giao nhau là cách chính xác. Dù sao, bạn có thể cho tôi tên của một cuốn sách nói rằng mối quan hệ 1: n (với sự tham gia tùy chọn ở bên: 1) nên được trình bày bằng một khóa ngoại duy nhất, tôi thích đọc những gì họ nói về chủ đề này.
Tom

Câu trả lời:


18

Hai mô hình đại diện cho các mối quan hệ khác nhau.

Bằng cách sử dụng bảng tham gia, bạn đang lập mô hình mối quan hệ nhiều-nhiều.

Bằng cách sử dụng khóa ngoại đơn giản, bạn đang lập mô hình mối quan hệ một-nhiều.

Nhược điểm của khóa ngoại không có giá trị là không thể mô hình hóa mối quan hệ nhiều-nhiều, nếu đó là những gì bạn đang cố gắng thực hiện.


Dựa trên chỉnh sửa của bạn cho câu hỏi, bạn đang chia bảng sinh viên thành hai bảng có cùng khóa. Tôi thường thấy điều này trên các bảng có quá nhiều lĩnh vực, vì vậy ai đó chia chúng thành hai để dễ quản lý hơn (tôi gọi nó là đặt son môi lên một con lợn).

Bằng cách tách bảng sinh viên, bạn tạo bảng thứ hai tùy chọn vì không cần bản ghi trong bảng thứ hai. Nó rất giống với một trường không cần thiết lập vì nó có thể là null.

Nếu bạn muốn có mối quan hệ một-nhiều, bạn nên sử dụng một bảng duy nhất và cho phép ID trường không có giá trị trong bảng sinh viên. Không có lý do để tránh null trong các trường, ngay cả đối với khóa ngoại. Điều đó biểu thị rằng mối quan hệ nước ngoài là tùy chọn: nhà phát triển và DBA hiểu rõ điều đó và công cụ cơ sở dữ liệu cơ bản chắc chắn sẽ hoạt động tốt.

Nếu bạn lo lắng về việc tham gia, đừng lo lắng. Có những ngữ nghĩa được xác định rõ về cách thức hoạt động của các phép nối với các trường null. Bằng cách sử dụng một bảng duy nhất, bạn có thể tham gia hai bảng thay vì ba.


Vì vậy, nếu tôi đang mô hình hóa mối quan hệ một-nhiều (với sự tham gia tùy chọn ở bên: 1), tôi có nên sử dụng khóa ngoại mặc dù thực tế là nó có thể có NULLgiá trị không?
Tom

1
@Tom vâng, đó chính xác là cách mô hình hóa nó. Mặc dù về mặt kỹ thuật có thể sử dụng bảng tham gia, mô hình dữ liệu cho phép nhiều người nên bạn sẽ cần các trình kích hoạt và logic cơ sở dữ liệu để ngăn chặn điều đó. Bạn tốt hơn bằng cách hạn chế mối quan hệ theo cách không thể thêm dữ liệu không chính xác.

1
Tôi chỉnh sửa câu hỏi của tôi. Tôi chỉ tạo student_idmột khóa chính trong School_has_Studentbảng, giữ mối quan hệ là một với nhiều người. Phương pháp này có nhược điểm gì khi sử dụng khóa ngoại?
Tom

@Tom Tôi chỉnh sửa câu trả lời của tôi.

7

Bạn đã viết trong một bình luận ở trên:

cuốn sách "Nguyên tắc cơ bản của hệ thống cơ sở dữ liệu" [...] nói rằng [...] rằng nên sử dụng bảng giao nhau nếu có nhiều giá trị NULL trong cột khóa ngoài (ví dụ: nếu 98% nhân viên không quản lý một bộ phận)

Khi có nhiều giá trị NULL trong cột khóa ngoài, các chương trình của bạn sẽ phải xử lý cột này hầu như trống cho mỗi và mọi bản ghi mà chúng xử lý. Cột có thể sẽ chiếm một số dung lượng đĩa mặc dù trong 98% trường hợp trống, truy vấn mối quan hệ có nghĩa là truy vấn cột đó cung cấp cho bạn nhiều lưu lượng mạng hơn và nếu bạn đang sử dụng ORM tạo ra các lớp từ các bảng của bạn, các chương trình của bạn cũng sẽ cần nhiều không gian hơn ở phía khách hàng hơn mức cần thiết. Sử dụng bảng giao cắt để tránh điều này, sẽ chỉ có các bản ghi liên kết cần thiết trong trường hợp khóa ngoại tương đương sẽ không phải là NULL.

Đối lập với điều đó, nếu bạn không chỉ có một vài giá trị NULL, giả sử 50% hoặc nhiều mối quan hệ không phải là NULL, sử dụng bảng giao nhau mang lại cho bạn hiệu ứng ngược lại - nhiều không gian đĩa hơn, độ phức tạp cao hơn dẫn đến lưu lượng mạng nhiều hơn, v.v.

Vì vậy, sử dụng bảng giao cắt chỉ là một hình thức tối ưu hóa, chỉ hợp lý cho một trường hợp cụ thể và đặc biệt là ngày nay, nơi không gian đĩa và bộ nhớ trở nên rẻ hơn, ít cần thiết hơn. Lưu ý rằng "Nguyên tắc cơ bản của hệ thống cơ sở dữ liệu" ban đầu được viết cách đây hơn 20 năm (tôi đã tìm thấy một tài liệu tham khảo cho phiên bản thứ hai từ năm 1994), và tôi đoán rằng khuyến nghị đã có ở đó vào thời điểm đó. Trước năm 1994, tối ưu hóa không gian có lẽ quan trọng hơn nhiều so với ngày nay, vì lưu trữ lớn vẫn còn đắt hơn và máy tính và mạng chậm hơn nhiều so với ngày nay.

Như một lưu ý phụ cho một nhận xét kén chọn: tuyên bố trên chỉ là cố gắng dự đoán những gì tác giả của "Nguyên tắc cơ bản của hệ thống cơ sở dữ liệu" đã nghĩ đến với khuyến nghị của mình, tôi đoán rằng ông đã đưa ra một tuyên bố chung chung, hợp lệ cho hầu hết các hệ thống. Trong một số cơ sở dữ liệu có các tối ưu hóa có thể khác như "các cột thưa thớt" khiến việc sử dụng bảng giao cắt trở nên lỗi thời hơn.

Vì vậy, đừng hiểu sai về đề xuất đó. Cuốn sách không cho bạn biết các bảng giao nhau cho các {0,1}:nmối quan hệ nói chung, hoặc - như bạn đã viết - rằng đây là "cách chính xác". Sử dụng tối ưu hóa như thế này sẽ làm cho chương trình của bạn phức tạp hơn chỉ khi bạn thực sự cần chúng.


Bạn đang giả định rất nhiều về việc triển khai cơ sở dữ liệu, đặc biệt là khi OP không đề cập đến một cơ sở dữ liệu cụ thể nào. Nhiều khả năng cơ sở dữ liệu đủ thông minh để chỉ sử dụng một lượng không gian nhỏ cho các cột thưa thớt.
vườn

@gardenhead: điều gì khiến bạn tin rằng đây là "nhiều khả năng"?
Doc Brown

Thực tế là cơ sở dữ liệu đã tồn tại trong nhiều thập kỷ và được tối ưu hóa cao vì chúng là một thành phần quan trọng của hầu hết các cơ sở hạ tầng.
vườn

@gardenhead: âm thanh với tôi bạn đang đưa ra những giả định phi lý hơn nhiều so với tôi. Tuy nhiên, xem chỉnh sửa của tôi.
Doc Brown

2

Mô hình khái niệm sẽ trông như thế này, điều này rất không chính thống để nói rằng ít hơn:

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

Mô hình vật lý sẽ trông như thế này, thật khó hiểu khi nói ít hơn (mọi người sẽ nghĩ đó là M: M trừ khi họ nhìn kỹ):

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

Đề xuất của tôi:

Nếu bạn thích, nhiều cột (FK hoặc cách khác), không áp dụng cho hầu hết các sinh viên, hãy tách các bảng thành các bảng vai trò với các rel 1: 1. Nhưng đó không phải vì chúng là FK, mà là vì các cột không áp dụng cho hầu hết các hàng.

Mặt khác , FK nullable là một phần bình thường của cơ sở dữ liệu và các bảng tham gia thường dành cho M: M rels.

Việc sử dụng phổ biến các rel 1: 1 là cho các bảng vai trò có các cột chỉ áp dụng nếu thực thể thuộc một loại nhất định và trích xuất các cột BLOB để xem xét hiệu suất hoặc lưu trữ. Việc mã hóa các giá trị null trong FK không phải là một cách sử dụng phổ biến cho điều đó.

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


2

Ngoài các câu trả lời khác, tôi muốn chỉ ra rằng giá trị null cho khóa ngoại là không rõ ràng. Có nghĩa là:

1) Trường học của học sinh (nếu có) không xác định (đây là ý nghĩa tiêu chuẩn của 'null' - giá trị không xác định)

2) Học sinh có học hay không và không có học sinh.

Nếu bạn sử dụng ý nghĩa tiêu chuẩn của null, làm thế nào bạn đại diện cho "sinh viên không có trường học" trong mô hình khóa ngoại của bạn. Trong trường hợp đó, có lẽ bạn phải tạo một mục "không có trường học", với id riêng trong bảng trường. (Không lý tưởng)


2
Cuốn sách "Nguyên tắc cơ bản của hệ thống cơ sở dữ liệu" đề cập rằng có 3 cách hiểu NULL, nó có thể có nghĩa: 1) Giá trị không xác định. 2) Không có sẵn hoặc giữ lại giá trị. 3) Không áp dụng thuộc tính (Tôi nghĩ cách giải thích này có nghĩa là bạn có thể chỉ định một NULLkhóa ngoại).
Tom

1
Đó là một danh sách hữu ích nhưng ngữ nghĩa của null (hoặc bất kỳ giá trị nào thực sự) đều có thể xác định được người dùng. Tức là nó có thể có nghĩa là bất cứ điều gì nhà thiết kế nói nó có nghĩa, không giới hạn trong danh sách đó. Vấn đề là làm thế nào để phân biệt các ý nghĩa khác nhau khi có thể yêu cầu nhiều hơn một (hoặc thậm chí được lưu vô tình)
Brad Thomas

Vì vậy, bạn có gợi ý rằng tôi nên tạo một bảng giao nhau thay vì sử dụng khóa ngoại không có giá trị?
Tom

@Tom Vâng, tôi tin rằng điều đó tốt hơn trong trường hợp này
Brad Thomas

@BradThomas - để tránh sự mơ hồ tương tự khi sử dụng bảng giao nhau, bạn có đại diện cho trường hợp 2 (được biết rằng học sinh không có trường học) bằng một bản ghi trong bảng giao nhau với NULL School_ID không?
andrew

1

Các bảng cơ sở dữ liệu có điều tốt đẹp này được gọi là các ràng buộc. Vì vậy, thật dễ dàng để thực hiện trong bảng giao nhau, chỉ cho phép 1 trong số mỗi học sinh xuất hiện trong bảng nhưng nhiều trường trong bảng đó. Hiệu quả mang lại cho bạn một

Lý thuyết là tốt nhưng cuối cùng bạn sẽ mô hình hóa cơ sở dữ liệu của bạn sau những câu hỏi bạn đang hỏi.

Nếu bạn muốn đặt câu hỏi thường xuyên với câu hỏi: "học sinh nào ở trường tôi" bạn có thực sự muốn truy vấn toàn bộ bảng học sinh hoặc có một bảng giao nhau dễ dàng.

Trong cơ sở dữ liệu: tối ưu hóa cho các câu hỏi bạn yêu cầu.


0

Có một trường hợp sử dụng trong đó sử dụng bảng thứ ba thực sự có ý nghĩa. Ví dụ có vẻ hoàn toàn là giả thuyết, nhưng tôi hy vọng nó minh họa tốt quan điểm của tôi. Giả sử bạn thêm nhiều cột vào studentsbảng và tại một số điểm, bạn quyết định thực thi tính duy nhất trên các bản ghi thông qua chỉ mục tổng hợp trên một số cột. Rất có khả năng bạn sẽ phải bao gồm cả school_idcột, và ở đây mọi thứ bắt đầu trở nên lộn xộn. Do cách SQL được thiết kế, chèn một số hồ sơ giống hệt nhau ở đâu school_idNULLsẽ thực hiện được. Nó có ý nghĩa hoàn hảo từ góc độ kỹ thuật, nhưng phản trực giác và có thể dẫn đến kết quả bất ngờ. Mặt khác, việc thực thi tính duy nhất trên bảng giao lộ là dễ dàng.

Tôi đã phải mô hình hóa một mối quan hệ "tùy chọn" như vậy gần đây, trong đó yêu cầu về một ràng buộc duy nhất là do một cột dấu thời gian. Để lại khóa ngoại không có giá trị trong bảng đột nhiên dẫn đến khả năng chèn các bản ghi có cùng dấu thời gian (giả sử đó là một mặc định, đặt trên các bản ghi chưa được kiểm tra / phê duyệt) - và cách duy nhất là loại bỏ cột nullable.

Vì vậy, như bạn có thể thấy, đó là một trường hợp khá cụ thể và như những người khác lưu ý, hầu hết các lần bạn sẽ hoàn toàn ổn với tất cả các NULLgiá trị. Nó thực sự phụ thuộc vào các yêu cầu cụ thể của mô hình của bạn.


0

Ngoài nhiều đề xuất hay đã được gửi, cá nhân tôi không phải là người hâm mộ các khóa ngoại trừ khi chúng thực sự cần thiết. Đầu tiên là mối quan hệ M: M mà bạn đang tham khảo. Ngoài ra, gọi một khóa ngoại và do đó kéo dữ liệu bảng đó vào các truy vấn của bạn, sẽ gây ra sự phức tạp hơn và tùy thuộc vào kích thước bảng, hiệu suất chậm hơn. Như những người khác đã nói, các trường FK không thể có thể không được hỗ trợ và có thể tạo ra các vấn đề toàn vẹn dữ liệu.

Nếu bạn đang xác định trạng thái nơi trường học sinh không xác định hoặc trống, NULL sẽ không phân biệt các điều kiện đó. (một lần nữa chúng tôi quay lại tính toàn vẹn dữ liệu.) Đề xuất bảng vai trò của Tulains là thanh lịch và cho phép các giá trị null sạch sẽ.

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.