Nullable Foreign Key thực hành không tốt?


114

Giả sử bạn có một bảng Đơn đặt hàng có khóa ngoại cho Id khách hàng. Bây giờ, giả sử bạn muốn thêm Đơn đặt hàng mà không có Mã khách hàng, (liệu điều đó có khả thi hay không là một câu hỏi khác), bạn sẽ phải đặt khóa ngoại NULL ... Đó có phải là phương pháp không tốt hay bạn muốn làm việc với bảng liên kết giữa Đơn hàng và Khách hàng? Mặc dù mối quan hệ là 1 đến n, một bảng liên kết sẽ biến nó thành n thành n. Mặt khác, với một bảng liên kết, tôi không có những NULLS đó nữa ...

Thực tế sẽ không có nhiều NULL trong cơ sở dữ liệu, bởi vì một bản ghi có khóa ngoại cho NULL chỉ là tạm thời cho đến khi khách hàng của đơn đặt hàng được thêm vào.

(Trong trường hợp của tôi, đó không phải là Đơn hàng và Khách hàng).

CHỈNH SỬA: Điều gì về một Khách hàng chưa được chỉ định để liên kết?


9
Đó là một trong những mục đích chính của việc có sẵn NULL trong lược đồ cơ sở dữ liệu. Hơn nữa, đó là lý do tại sao bạn có thể khai báo các trường NULL hoặc NOT NULL, để có thể đáp ứng các yêu cầu cụ thể của lược đồ của bạn.
gahooa

7
Ban đầu tôi đọc những câu hỏi như Nullable Tiểu phím, và sắp sửa lội với một số lời khuyên mạnh mẽ ... :-)
Andrzej Doyle

Câu trả lời:


51

Có bảng liên kết có lẽ là một lựa chọn tốt hơn. Ít nhất nó không vi phạm BCNF chuẩn hóa (dạng bình thường Boyce-Codd). tuy nhiên, tôi thích thực dụng. Nếu bạn có rất ít giá trị null này và chúng chỉ là tạm thời, tôi nghĩ bạn nên bỏ qua bảng liên kết vì nó chỉ làm tăng thêm độ phức tạp cho lược đồ.

Còn một chú ý đáng nói; sử dụng bảng liên kết không nhất thiết phải biến nó thành n, nếu bạn trong bảng liên kết sử dụng khóa ngoại trỏ đến bảng đơn hàng của bạn làm khóa chính trong bảng liên kết đó thì mối quan hệ vẫn là 1..n. Chỉ có thể có một mục nhập trong bảng liên kết đó cho mỗi đơn đặt hàng.


2
source__destination_link hoặc SourceDestination
Svisstack

7
Tôi muốn nghe về một tình huống khi có một bảng liên kết thì tốt hơn, tôi chưa bao giờ gặp phải tình huống mà nó sẽ được cải thiện luồng quy trình theo bất kỳ cách nào.
Reimius

5
Như đã chỉ ra trong câu trả lời của tôi, tôi sẽ thực dụng trong trường hợp cụ thể này và không sử dụng bảng liên kết. Tôi chắc chắn rằng các biểu mẫu bình thường không được phát minh ra để cải thiện quy trình mà là để đảm bảo tính nhất quán và tránh dư thừa. Đó là một cuộc thảo luận rất chung chung, tôi nghĩ rằng nó phải được xem xét trên cơ sở từng trường hợp.
Patrik Hägne

110

Không Không có gì sai với Nullable FKs. Điều này thường xảy ra khi đối tượng mà FK trỏ đến có mối quan hệ (không hoặc một) đến (1 hoặc nhiều) với bảng tham chiếu Khóa chính.

Một ví dụ có thể là nếu bạn có cả thuộc tính Địa chỉ thực và thuộc tính Địa chỉ gửi thư (cột) trong một bảng, với FK đến một bảng Địa chỉ. Bạn có thể đặt Địa chỉ thực là vô hiệu để xử lý khi đối tượng chỉ có hộp thư bưu điện (địa chỉ gửi thư) và địa chỉ gửi thư không thể xử lý khi địa chỉ gửi thư giống với địa chỉ thực (hoặc không).


39

Các cột vô hiệu có thể ở 1NF đến 5NF, nhưng không phải trong 6NF theo những gì tôi đã đọc.

Chỉ khi bạn biết rõ hơn Chris Date "hình thức bình thường đầu tiên thực sự có nghĩa là gì". Nếu cả x và y đều có giá trị rỗng, và thực sự trong một số hàng x và y đều là giá trị nullthì WHERE x=ykhông có kết quả true. Điều này chứng tỏ rằng null không phải là một giá trị (bởi vì bất kỳ giá trị thực nào luôn bằng với chính nó). Và vì RM quy định rằng "phải có một giá trị trong mỗi ô của bảng", bất kỳ thứ nào có thể chứa null đều không phải là thứ quan hệ, và do đó câu hỏi về 1NF thậm chí không nảy sinh.

Tôi đã nghe nó tranh luận rằng các cột Nullable nói chung phá vỡ mức độ chuẩn hóa đầu tiên.

Hãy xem ở trên để biết lý do chính đáng bên dưới lập luận đó.

Nhưng trong thực tế, nó rất thực tế.

Chỉ khi bạn miễn nhiễm với những cơn đau đầu mà nó thường gây ra cho toàn bộ phần còn lại của thế giới. Một vấn đề đau đầu như vậy (và nó chỉ là một vấn đề nhỏ, so với các nullhiện tượng khác ) là thực tế rằng WHERE x=ytrong SQL thực sự có nghĩa WHERE x is not null and y is not null and x=y, nhưng hầu hết các lập trình viên chỉ đơn giản là không nhận thức được thực tế đó và chỉ đọc qua nó. Đôi khi không có bất kỳ tác hại nào, những lần khác thì không.

Trên thực tế, các cột có giá trị rỗng vi phạm một trong những quy tắc thiết kế cơ sở dữ liệu cơ bản nhất: không kết hợp các phần tử thông tin riêng biệt trong một cột. Null thực hiện chính xác điều đó bởi vì chúng kết hợp giá trị boolean "trường này / không thực sự hiện diện" với giá trị thực.


18
+1 cho "WHERE x không rỗng và y không rỗng và x = y". Không nhận thức được điều đó.
RobM

1
Lập luận và ví dụ được bố trí rất độc đáo.
pedz

1
Một vấn đề. Khi giá trị "không tồn tại" (LÀ kịch bản trong thế giới thực) và thuộc tính cơ sở dữ liệu không cho phép giá trị rỗng, bất kỳ giá trị nào trong thuộc tính đều SAI. Đối với những vấn đề đau đầu, hãy nhớ HÔN, nó không chỉ có nghĩa là giữ cho nó đơn giản, nó có nghĩa là Giữ nó càng đơn giản càng tốt, nhưng không đơn giản hơn. Nếu "mô hình quan hệ" yêu cầu một kết quả không thực tế, ngu ngốc, thì có lẽ các quy tắc cần phải mở rộng để xử lý dữ liệu thế giới thực cần thiết là gì?
Charles Bretana

1
Người ta đã chỉ ra rằng logic ba giá trị dẫn đến nhu cầu logic bốn giá trị và điều đó dẫn đến nhu cầu logic năm giá trị, v.v. v.v ... Logic 2 giá trị đủ, nhưng cấu trúc dữ liệu chúng ta nhận được khi áp dụng nó làm cho "càng đơn giản càng tốt" vẫn kém đơn giản hơn nhiều so với "đơn giản như chúng tôi muốn".
Erwin Smout

2
Chris Date, Logic & Databases, Chpt 6, "Tại sao logic DBMS quan hệ không được có nhiều giá trị", trang 145. Danh sách các tài liệu tham khảo đến chương đó cũng phải thú vị, đặc biệt là những tài liệu liên quan đến McGoveran.
Erwin Smout

13

Tôi không thể thấy có gì sai khi nó chỉ là một mối quan hệ n-1 tùy chọn sẽ được biểu diễn bằng giá trị null trong khóa ngoại. Ngược lại, nếu bạn đặt bảng liên kết của mình thì bạn sẽ phải quản lý rằng nó không trở thành một mối quan hệ nn, vì vậy sẽ gây ra nhiều rắc rối hơn.


2
Thực ra đó là mối quan hệ 0-N, không phải mối quan hệ 1-N tùy chọn. Nhưng tôi đồng ý với bạn.
Eric J.

5
Quản lý? Đó là một ràng buộc DUY NHẤT đơn giản ở phía 0-1!
wqw

2
Có nó là một hạn chế UNIQUE, nhưng bạn cũng sẽ phải đối phó với trường hợp ngoại lệ có thể sau này với trong mã của bạn do ràng buộc ...
pedromarce

4

Các mối quan hệ tùy chọn chắc chắn có thể có trong mô hình quan hệ.

Bạn có thể sử dụng null để thể hiện sự vắng mặt của một mối quan hệ. Chúng rất tiện lợi, nhưng chúng sẽ khiến bạn đau đầu giống như những thứ vô hiệu gây ra cho bạn ở những nơi khác. Một nơi mà họ không gây ra bất kỳ rắc rối nào là tham gia. Các hàng có giá trị rỗng trong khóa ngoại không khớp với bất kỳ hàng nào trong bảng được tham chiếu. Vì vậy, họ bỏ ra khỏi một gia nhập nội bộ. Nếu bạn thực hiện các phép nối bên ngoài, bạn sẽ phải đối mặt với null.

Nếu bạn thực sự muốn tránh null (hình thức bình thường thứ 6), bạn có thể phân rã bảng. Một trong hai bảng đã phân tách có hai cột khóa ngoại. Một là khóa ngoại tùy chọn mà bạn có và khóa kia là khóa ngoại tham chiếu đến khóa chính của bảng gốc. Bây giờ bạn phải sử dụng các ràng buộc để ngăn mối quan hệ trở nên nhiều-nhiều, bạn muốn ngăn chặn điều đó.


2

Sử dụng NULL sẽ là một cách tốt để xóa các đơn hàng chưa hoàn thành:

SELECT * FROM `orders`
WHERE `started_time` < (UNIX_TIMESTAMP() + 900) AND `customer_id` IS NULL

Ở trên sẽ hiển thị các đơn đặt hàng cũ hơn 15 phút mà không có ID khách hàng liên quan.


1

Nếu bạn chỉ thêm đơn hàng tạm thời mà không có id khách hàng cho đến khi xác định được khách hàng, thì việc thêm khách hàng và đặt hàng trong một giao dịch sẽ không đơn giản hơn, do đó loại bỏ nhu cầu nhập khóa ngoại NULL và tránh bất kỳ ràng buộc hoặc kích hoạt nào bạn đã thiết lập để bị vi phạm?

Thông thường, tình huống này phát sinh trong các ứng dụng web nơi đơn đặt hàng được trình bày chi tiết trước khi khách hàng xác định họ là ai. Và trong những tình huống đó, đơn đặt hàng được giữ ở trạng thái máy chủ hoặc trong cookie cho đến khi tất cả trạng thái cần thiết cho một đơn đặt hàng hoàn chỉnh được cung cấp tại thời điểm đó đơn đặt hàng được lưu giữ trong cơ sở dữ liệu.

Khóa ngoại NULL là ok cho những thứ như địa chỉ, như đã đề cập ở trên. Nhưng trường khách hàng NULL không có ý nghĩa đối với một đơn đặt hàng và nên bị hạn chế.


Khách hàng đặt hàng là một ví dụ. Trong ứng dụng của tôi, idd giống địa chỉ hơn. Không thể tìm thấy ngay một ví dụ đúng theo mọi cách. cám ơn.
Lieven Cardoen

1
Đây có thể là một tình huống hợp lệ nếu cơ sở dữ liệu đang được sử dụng để lưu trữ các mặt hàng trong giỏ hàng, trong đó giỏ hàng không thuộc về người dùng đã đăng ký.
Johnie Karr

1

Bạn luôn có thể thêm một hàng giả vào bảng Khách hàng của mình, chẳng hạn như Id = -1 và CustomerName = 'Unknown', sau đó trong trường hợp thông thường bạn đặt CustomerId của mình trong Order NULL, hãy đặt nó thành -1.

Điều này cho phép bạn không có FK có thể nullable nhưng vẫn thể hiện sự thiếu dữ liệu một cách thích hợp (và sẽ giúp bạn tránh khỏi những người dùng phía dưới không biết cách đối phó với NULL).


Chỉ cần thêm vào điều này, hãy nhớ rằng NULLS không được lưu trữ trong một chỉ mục (trong oracle), vì vậy điều này có nghĩa là bỏ qua bảng liên kết và chuyển sang FK có thể trống sẽ có ý nghĩa - hiệu suất khôn ngoan. Một điều khác mà nó có thể phụ thuộc là nếu bạn muốn lưu trữ bất kỳ thứ gì khác trong bảng liên kết này, ví dụ: WHO đã tạo liên kết và khi nào? Liên kết hiện không hoạt động / đã bị xóa (nhưng đã từng là?)
Worthy7

Đây là một ý tưởng tồi. Nếu bạn có khóa ngoại được đặt và dữ liệu mà nó trỏ đến sau đó bị xóa, bạn sẽ không nhận được ngoại lệ khóa ngoại và bây giờ dữ liệu của bạn là vô nghĩa. Tệ hơn nữa, nếu cái gì khác là sau này giao cho chìa khóa mà bạn đang trỏ đến hoàn toàn khách hàng sai
IcedDante

0

Các FK vô hiệu cho các quan hệ nhiều-một tùy chọn là hoàn toàn ổn.


-1

Tôi đã nghe nó tranh luận rằng các cột Nullable nói chung đang phá vỡ mức độ chuẩn hóa đầu tiên. Nhưng trong thực tế, nó rất thực tế.


3
Các cột vô hiệu có thể ở 1NF đến 5NF, nhưng không phải trong 6NF theo những gì tôi đã đọc.
Walter Mitty

-1

Có, có gì đó sai. Nó không phải là khóa ngoại nếu nó có giá trị nullable. Thiết kế cơ sở dữ liệu của nó bằng mã. Có thể bạn tạo một liên kết không đến chưa được chỉ định. hoặc "Chưa được gán" nếu bạn sử dụng ký tự col. Giữ 100% tính toàn vẹn của dữ liệu của bạn.

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.