it-swarm-vi.tech

Có gì sai với khóa ngoại?

Tôi nhớ đã nghe Joel Spolsky đề cập đến trong podcast 014 rằng anh ấy hầu như không bao giờ sử dụng khóa ngoại (nếu tôi nhớ chính xác). Tuy nhiên, với tôi chúng có vẻ khá quan trọng để tránh trùng lặp và các vấn đề toàn vẹn dữ liệu tiếp theo trong toàn bộ cơ sở dữ liệu của bạn.

Mọi người có một số lý do chắc chắn là tại sao (để tránh một cuộc thảo luận trong các dòng với các nguyên tắc Stack Overflow) không?

Chỉnh sửa: "Tôi chưa có lý do để tạo khóa ngoại, vì vậy đây có thể là lý do đầu tiên của tôi để thực sự thiết lập một. "

247
ljs

Lý do nên sử dụng Khóa ngoại:

  • bạn sẽ không nhận được hàng mồ côi
  • bạn có thể có hành vi "xóa xóa", tự động dọn dẹp các bảng
  • hiểu biết về các mối quan hệ giữa các bảng trong cơ sở dữ liệu giúp Trình tối ưu hóa lập kế hoạch truy vấn của bạn để thực hiện hiệu quả nhất, vì nó có thể có được ước tính tốt hơn về tính chính xác của việc tham gia.
  • Các FK đưa ra một gợi ý khá lớn về những thống kê nào là quan trọng nhất để thu thập trên cơ sở dữ liệu, từ đó dẫn đến hiệu suất tốt hơn
  • chúng cho phép tất cả các loại hỗ trợ được tạo tự động - ORM có thể tự tạo, các công cụ trực quan sẽ có thể tạo bố cục lược đồ Nice cho bạn, v.v.
  • ai đó mới tham gia dự án sẽ hòa nhập vào mọi thứ nhanh hơn vì các mối quan hệ ngầm được ghi lại rõ ràng

Lý do không sử dụng Khóa ngoại:

  • bạn đang làm cho DB hoạt động thêm trên mọi hoạt động CRUD vì nó phải kiểm tra tính nhất quán của FK. Đây có thể là một chi phí lớn nếu bạn có nhiều tiền
  • bằng cách thực thi các mối quan hệ, các FK chỉ định một thứ tự mà bạn phải thêm/xóa mọi thứ, điều này có thể dẫn đến việc DB từ chối thực hiện những gì bạn muốn. (Được cấp, trong những trường hợp như vậy, những gì bạn đang cố gắng làm là tạo ra một Hàng mồ côi và đó thường không phải là một điều tốt). Điều này đặc biệt đau đớn khi bạn đang thực hiện cập nhật hàng loạt lớn và bạn tải lên một bảng trước một bảng khác, với bảng thứ hai tạo trạng thái nhất quán (nhưng bạn nên thực hiện loại điều đó nếu có khả năng tải thứ hai không thành công và cơ sở dữ liệu bây giờ không nhất quán?).
  • đôi khi bạn biết trước dữ liệu của mình sẽ bị bẩn, bạn chấp nhận điều đó và bạn muốn DB chấp nhận nó
  • bạn chỉ lười biếng :-)

Tôi nghĩ (tôi không chắc chắn!) Rằng hầu hết các cơ sở dữ liệu được thiết lập đều cung cấp một cách để chỉ định khóa ngoại không được thi hành và chỉ đơn giản là một chút siêu dữ liệu. Vì việc không thực thi xóa sạch mọi lý do không sử dụng FK, có lẽ bạn nên đi theo lộ trình đó nếu có bất kỳ lý do nào trong phần thứ hai được áp dụng.

344
SquareCog

Đây là một vấn đề của giáo dục. Nếu ở đâu đó trong sự nghiệp giáo dục hoặc nghề nghiệp của bạn mà bạn dành thời gian cho ăn và chăm sóc cơ sở dữ liệu (hoặc làm việc chặt chẽ với những người tài năng đã làm), thì các nguyên lý cơ bản của các thực thể và mối quan hệ đã ăn sâu vào quá trình suy nghĩ của bạn. Trong số những sơ suất đó là làm thế nào/khi/tại sao để chỉ định các khóa trong cơ sở dữ liệu của bạn (chính, nước ngoài và có lẽ thay thế). Đó là bản chất thứ hai.

Tuy nhiên, nếu bạn chưa có trải nghiệm kỹ lưỡng hoặc tích cực như vậy trong quá khứ với các nỗ lực liên quan đến RDBMS, thì có khả năng bạn chưa tiếp xúc với thông tin đó. Hoặc có lẽ quá khứ của bạn bao gồm cả việc chìm đắm trong một môi trường chống lại cơ sở dữ liệu rõ ràng (ví dụ: "những DBA đó là những kẻ ngốc - chúng tôi rất ít, chúng tôi đã chọn một vài trình xử lý mã Java/c # sẽ cứu ngày"), trong trường hợp đó bạn có thể phản đối kịch liệt với những tiếng bập bẹ của một số người ngu ngốc nói với bạn rằng FK (và các ràng buộc mà họ có thể ám chỉ) thực sự quan trọng nếu bạn chỉ lắng nghe.

Hầu hết mọi người đều được dạy khi họ còn nhỏ rằng đánh răng là quan trọng. Bạn có thể nhận được mà không có nó? Chắc chắn, nhưng ở đâu đó, bạn sẽ có ít răng hơn nếu bạn chải răng sau mỗi bữa ăn. Nếu cha mẹ có trách nhiệm đủ để trang trải thiết kế cơ sở dữ liệu cũng như vệ sinh răng miệng, chúng ta sẽ không có cuộc trò chuyện này. :-)

79
Ed Lucas

Tôi chắc chắn có rất nhiều ứng dụng mà bạn có thể thoát khỏi nó, nhưng đó không phải là ý tưởng tốt nhất. Bạn không thể luôn tin tưởng vào ứng dụng của mình để quản lý cơ sở dữ liệu của mình một cách chính xác và việc quản lý cơ sở dữ liệu một cách thẳng thắn không phải là mối quan tâm lớn đối với ứng dụng của bạn.

Nếu bạn đang sử dụng cơ sở dữ liệu quan hệ thì có vẻ như bạn phải có một số mối quan hệ được xác định trong đó. Thật không may, thái độ này (bạn không cần khóa ngoại) dường như được chấp nhận bởi rất nhiều nhà phát triển ứng dụng, những người không muốn bị làm phiền với những thứ ngớ ngẩn như tính toàn vẹn dữ liệu (nhưng cần vì công ty của họ không có nhà phát triển cơ sở dữ liệu chuyên dụng). Thông thường trong các cơ sở dữ liệu được kết hợp bởi các loại này, bạn thật may mắn khi có các khóa chính;)

52
AlexCuse

Khóa ngoại là thiết yế cho bất kỳ mô hình cơ sở dữ liệu quan hệ nào.

40
Galwegian

Tôi luôn sử dụng chúng, nhưng sau đó tôi tạo cơ sở dữ liệu cho các hệ thống tài chính. Cơ sở dữ liệu là phần quan trọng của ứng dụng. Nếu dữ liệu trong cơ sở dữ liệu tài chính không hoàn toàn chính xác thì thực sự không quan trọng bạn bỏ bao nhiêu công sức vào mã/thiết kế mặt trước của mình. Bạn đang lãng phí thời gian của bạn.

Ngoài ra còn có một thực tế là nhiều hệ thống thường cần giao tiếp trực tiếp với cơ sở dữ liệu - từ các hệ thống khác chỉ đọc dữ liệu (Báo cáo tinh thể) đến các hệ thống chèn dữ liệu (không nhất thiết phải sử dụng API tôi đã thiết kế; có thể được viết bởi một người quản lý buồn tẻ vừa phát hiện ra VBScript và có mật khẩu SA cho hộp SQL). Nếu cơ sở dữ liệu không phải là bằng chứng ngu ngốc như nó có thể, thì tạm biệt cơ sở dữ liệu.

Nếu dữ liệu của bạn là quan trọng, thì có, sử dụng khóa ngoại, tạo một bộ thủ tục được lưu trữ để tương tác với dữ liệu và tạo DB khó nhất mà bạn có thể. Nếu dữ liệu của bạn không quan trọng, tại sao bạn bắt đầu tạo cơ sở dữ liệu?

29
Ant

Cập nhật : Bây giờ tôi luôn sử dụng khóa ngoại. Câu trả lời của tôi cho sự phản đối "họ kiểm tra phức tạp" là "viết các bài kiểm tra đơn vị của bạn để họ hoàn toàn không cần cơ sở dữ liệu. Mọi bài kiểm tra sử dụng cơ sở dữ liệu nên sử dụng đúng cách và bao gồm các khóa ngoại. tìm một cách ít đau đớn hơn để thực hiện thiết lập. "


Khóa ngoại làm phức tạp kiểm tra tự động

Giả sử bạn đang sử dụng khóa ngoại. Bạn đang viết một bài kiểm tra tự động có nội dung "khi tôi cập nhật tài khoản tài chính, nó sẽ lưu bản ghi giao dịch." Trong thử nghiệm này, bạn chỉ quan tâm đến hai bảng: accountstransactions.

Tuy nhiên, accounts có khóa ngoại là contractscontracts có fk thành clientsclients có fk thành citiescities có fk thành states.

Bây giờ cơ sở dữ liệu sẽ không cho phép bạn chạy thử nghiệm mà không thiết lập dữ liệu trong bốn bảng không liên quan đến thử nghiệm của bạn .

Có ít nhất hai quan điểm có thể về điều này:

  • "Đó là một điều tốt: thử nghiệm của bạn phải thực tế và những hạn chế dữ liệu đó sẽ tồn tại trong sản xuất."
  • "Đó là một điều tồi tệ: bạn sẽ có thể đơn vị kiểm tra các phần của hệ thống mà không liên quan đến các phần khác. Bạn có thể thêm các bài kiểm tra tích hợp cho toàn bộ hệ thống."

Cũng có thể tạm thời tắt kiểm tra khóa ngoại trong khi chạy kiểm tra. MySQL, ít nhất, hỗ trợ này .

19
Nathan Long

"Họ có thể làm cho việc xóa các bản ghi trở nên cồng kềnh hơn - bạn không thể xóa bản ghi" chính "trong đó có các bản ghi trong các bảng khác nơi các khóa ngoại sẽ vi phạm ràng buộc đó."

Điều quan trọng cần nhớ là tiêu chuẩn SQL xác định các hành động được thực hiện khi khóa ngoại bị xóa hoặc cập nhật. Những cái tôi biết là:

  • ON DELETE RESTRICT - Ngăn chặn mọi hàng trong bảng khác có khóa trong cột này khỏi bị xóa. Đây là những gì Ken Ray đã mô tả ở trên.
  • ON DELETE CASCADE - Nếu một hàng trong bảng khác bị xóa, hãy xóa bất kỳ hàng nào trong bảng này tham chiếu đến nó.
  • ON DELETE SET DEFAULT - Nếu một hàng trong bảng khác bị xóa, hãy đặt bất kỳ khóa ngoại nào tham chiếu đến mặc định của cột.
  • ON DELETE SET NULL - Nếu một hàng trong bảng khác bị xóa, hãy đặt bất kỳ khóa ngoại nào tham chiếu nó trong bảng này thành null.
  • ON DELETE NO ACTION - Khóa ngoại này chỉ đánh dấu rằng đó là khóa ngoại; cụ thể là để sử dụng trong OR mapper.

Những hành động tương tự này cũng áp dụng cho ON UPDATE.

Mặc định dường như phụ thuộc vào máy chủ sql mà bạn đang sử dụng.

14
Powerlord

@imphasing - đây chính xác là kiểu suy nghĩ gây ra ác mộng bảo trì.

Tại sao oh tại sao bạn lại bỏ qua tính toàn vẹn tham chiếu khai báo, trong đó dữ liệu có thể được bảo đảm để ít nhất là nhất quán, ủng hộ cái gọi là "thực thi phần mềm" là biện pháp phòng ngừa yếu nhất.

14
Ed Guiness

Có một lý do chính đáng để không sử dụng chúng: Nếu bạn không hiểu vai trò của họ hoặc cách sử dụng chúng.

Trong các tình huống sai, các ràng buộc khóa ngoại có thể dẫn đến sự nhân rộng của thác nước. Nếu ai đó xóa bản ghi sai, hoàn tác nó có thể trở thành nhiệm vụ voi ma mút.

Ngoài ra, ngược lại, khi bạn cần loại bỏ một cái gì đó, nếu được thiết kế kém, các ràng buộc có thể gây ra tất cả các loại khóa ngăn cản bạn.

12
Kent Fredric

Không có tốt lý do không để sử dụng chúng ... trừ khi các hàng mồ côi không phải là vấn đề lớn với bạn .

11
Matt Rogish

Câu hỏi lớn hơn là: bạn có lái xe bịt mắt không? Đó là cách mà nếu bạn phát triển một hệ thống không có ràng buộc tham chiếu. Hãy nhớ rằng các yêu cầu nghiệp vụ thay đổi, thay đổi thiết kế ứng dụng, các giả định logic tương ứng trong các thay đổi mã, bản thân logic có thể được cấu trúc lại, v.v. Nói chung, các ràng buộc trong cơ sở dữ liệu được đặt theo các giả định logic hiện đại, dường như chính xác cho các xác nhận và giả định logic cụ thể.

Thông qua vòng đời của một ứng dụng, tham chiếu và kiểm tra dữ liệu ràng buộc việc thu thập dữ liệu của cảnh sát thông qua ứng dụng, đặc biệt là khi các yêu cầu mới thúc đẩy ứng dụng logic thay đổi.

Theo chủ đề của danh sách này - khóa ngoại không tự "cải thiện hiệu suất", cũng không "làm giảm hiệu suất" đáng kể từ quan điểm của hệ thống xử lý giao dịch thời gian thực. Tuy nhiên, có một chi phí tổng hợp để kiểm tra ràng buộc trong hệ thống "lô" khối lượng CAO. Vì vậy, đây là sự khác biệt, thời gian thực so với quy trình giao dịch hàng loạt; xử lý hàng loạt - trong đó chi phí được xử lý, phải chịu bởi các kiểm tra ràng buộc, của một lô được xử lý tuần tự đặt ra một cú đánh hiệu suất.

Trong một hệ thống được thiết kế tốt, kiểm tra tính nhất quán dữ liệu sẽ được thực hiện "trước khi" xử lý một lô thông qua (tuy nhiên, cũng có một chi phí liên quan ở đây); do đó, kiểm tra ràng buộc khóa ngoại không được yêu cầu trong thời gian tải. Trong thực tế, tất cả các ràng buộc, bao gồm cả khóa ngoại, nên tạm thời bị vô hiệu hóa cho đến khi lô được xử lý.

QUERY HIỆU SUẤT - nếu các bảng được nối trên khóa ngoại, hãy nhận thức được thực tế rằng các cột khóa ngoại không bị CHỈ ĐỊNH (mặc dù khóa chính tương ứng được lập chỉ mục theo định nghĩa). Bằng cách lập chỉ mục một khóa ngoại, đối với vấn đề đó, bằng cách lập chỉ mục bất kỳ khóa nào và tham gia các bảng trên được lập chỉ mục sẽ giúp thực hiện tốt hơn, chứ không phải bằng cách tham gia vào khóa không được lập chỉ mục với ràng buộc khóa ngoại đối với khóa đó.

Thay đổi chủ đề, nếu cơ sở dữ liệu chỉ hỗ trợ hiển thị/hiển thị nội dung trang web/vv và ghi lại các nhấp chuột, thì cơ sở dữ liệu có đầy đủ các ràng buộc trên tất cả các bảng sẽ bị hủy vì các mục đích đó. Hãy suy nghĩ về nó. Hầu hết các trang web don don thậm chí sử dụng một cơ sở dữ liệu như vậy. Đối với các yêu cầu tương tự, khi dữ liệu chỉ được ghi lại và không được tham chiếu mỗi lần nói, hãy sử dụng cơ sở dữ liệu trong bộ nhớ, không có ràng buộc. Điều này không có nghĩa là không có mô hình dữ liệu, có mô hình logic, nhưng không có mô hình dữ liệu vật lý.

4
jasbir L

Theo kinh nghiệm của tôi, tốt hơn hết là tránh sử dụng FK trong các ứng dụng quan trọng của cơ sở dữ liệu. Tôi sẽ không đồng ý với những người ở đây nói rằng FK là một cách thực hành tốt nhưng nó không thực tế khi cơ sở dữ liệu rất lớn và có các hoạt động CRUD/giây rất lớn. Tôi có thể chia sẻ mà không cần đặt tên ... một trong những ngân hàng đầu tư lớn nhất không có FK duy nhất trong cơ sở dữ liệu. Các ràng buộc này được xử lý bởi các lập trình viên trong khi tạo các ứng dụng liên quan đến DB. Lý do cơ bản là khi bao giờ một CRUD mới được thực hiện, nó phải tạo ra nhiều bảng và xác minh cho mỗi lần chèn/cập nhật, mặc dù điều này sẽ không phải là vấn đề lớn đối với các truy vấn ảnh hưởng đến các hàng đơn lẻ nhưng nó tạo ra độ trễ rất lớn khi bạn xử lý xử lý hàng loạt mà bất kỳ ngân hàng lớn nào phải làm như nhiệm vụ hàng ngày.

Tốt hơn hết là tránh FK nhưng rủi ro của nó phải được xử lý bởi các lập trình viên.

3
Rachit

"Trước khi thêm bản ghi, hãy kiểm tra xem bản ghi tương ứng có tồn tại trong bảng khác không" là logic nghiệp vụ.

Dưới đây là một số lý do bạn không muốn điều này trong cơ sở dữ liệu:

  1. Nếu quy tắc kinh doanh thay đổi, bạn phải thay đổi cơ sở dữ liệu. Cơ sở dữ liệu sẽ cần tạo lại chỉ mục trong rất nhiều trường hợp và điều này chậm trên các bảng lớn. (Thay đổi quy tắc bao gồm: cho phép khách đăng tin nhắn hoặc cho phép người dùng xóa tài khoản của họ mặc dù đã đăng bình luận, v.v.).

  2. Thay đổi cơ sở dữ liệu không dễ như triển khai sửa lỗi phần mềm bằng cách đẩy các thay đổi vào kho lưu trữ sản xuất. Chúng tôi muốn tránh thay đổi cấu trúc cơ sở dữ liệu càng nhiều càng tốt. Càng có nhiều logic kinh doanh trong cơ sở dữ liệu, bạn càng tăng cơ hội cần thay đổi databae (và kích hoạt lập chỉ mục lại).

  3. TDD. Trong các bài kiểm tra đơn vị, bạn có thể thay thế cơ sở dữ liệu cho các giả và kiểm tra chức năng. Nếu bạn có bất kỳ logic nghiệp vụ nào trong cơ sở dữ liệu của mình, bạn không thực hiện các kiểm tra hoàn chỉnh và sẽ cần kiểm tra với cơ sở dữ liệu hoặc sao chép logic nghiệp vụ trong mã cho mục đích thử nghiệm, sao chép logic và tăng khả năng logic không hoạt động trong cùng một cách.

  4. Sử dụng lại logic của bạn với các nguồn dữ liệu khác nhau. Nếu không có logic trong cơ sở dữ liệu, ứng dụng của tôi có thể tạo các đối tượng từ các bản ghi từ cơ sở dữ liệu, tạo chúng từ một dịch vụ web, tệp json hoặc bất kỳ nguồn nào khác. Tôi chỉ cần trao đổi việc thực hiện ánh xạ dữ liệu và có thể sử dụng tất cả logic kinh doanh của mình với bất kỳ nguồn nào. Nếu có logic trong cơ sở dữ liệu, điều này là không thể và bạn phải triển khai logic ở lớp trình ánh xạ dữ liệu hoặc trong logic nghiệp vụ. Dù bằng cách nào, bạn cần những kiểm tra trong mã của bạn. Nếu không có logic trong cơ sở dữ liệu, tôi có thể triển khai ứng dụng ở các vị trí khác nhau bằng cách sử dụng các cơ sở dữ liệu hoặc tệp phẳng khác nhau.

3
Tom B

Lý do bổ sung để sử dụng Khóa ngoài: - Cho phép sử dụng lại cơ sở dữ liệu nhiều hơn

Lý do bổ sung để KHÔNG sử dụng Khóa ngoại: - Bạn đang cố gắng khóa khách hàng vào công cụ của mình bằng cách giảm sử dụng lại.

3
Dan

Tôi đồng ý với các câu trả lời trước đó ở chỗ chúng rất hữu ích để bảo đảm tính nhất quán của dữ liệu. Tuy nhiên, có một bài viết thú vị của Jeff Atwood vài tuần trước đã thảo luận về ưu và nhược điểm của dữ liệu chuẩn hóa và nhất quán.

Nói cách khác, một cơ sở dữ liệu không chuẩn hóa có thể nhanh hơn khi xử lý lượng dữ liệu khổng lồ; và bạn có thể không quan tâm đến tính nhất quán chính xác tùy thuộc vào ứng dụng, nhưng điều đó buộc bạn phải cẩn thận hơn nhiều khi xử lý dữ liệu, vì DB sẽ không như vậy.

2
Santiago Palladino

Cơ sở dữ liệu Clarify là một ví dụ về cơ sở dữ liệu thương mại không có khóa chính hoặc khóa ngoài.

http://www.geekinterview.com/question_details/18869

Điều thú vị là, tài liệu kỹ thuật có độ dài lớn để giải thích các bảng có liên quan như thế nào, sử dụng cột nào để tham gia chúng, v.v.

Nói cách khác, họ có thể đã tham gia các bảng với khai báo rõ ràng (DRI) nhưng họ đã chọn không .

Do đó, cơ sở dữ liệu Clarify chứa đầy sự không nhất quán và nó hoạt động kém.

Nhưng tôi cho rằng nó làm cho các nhà phát triển làm việc dễ dàng hơn, không phải viết mã để xử lý tính toàn vẹn tham chiếu như kiểm tra các hàng liên quan trước khi xóa, thêm.

Và điều đó, tôi nghĩ, là lợi ích chính của việc không có các ràng buộc khóa ngoài trong cơ sở dữ liệu quan hệ. Nó làm cho nó dễ dàng hơn để phát triển, ít nhất đó là từ quan điểm có thể quan tâm đến ma quỷ.

2
Ed Guiness

Tôi chỉ biết cơ sở dữ liệu Oracle, không có cơ sở dữ liệu nào khác và tôi có thể nói rằng Khóa ngoài là điều cần thiết để duy trì tính toàn vẹn dữ liệu. Trước khi chèn dữ liệu, cấu trúc dữ liệu cần được thực hiện và được thực hiện chính xác. Khi điều đó được thực hiện - và do đó, tất cả các khóa chính VÀ khóa ngoài được tạo - công việc đã hoàn tất!

Ý nghĩa: hàng mồ côi? Không bao giờ thấy điều đó trong cuộc sống của tôi. Trừ khi một lập trình viên tồi quên khóa ngoại, hoặc nếu anh ta thực hiện nó ở cấp độ khác. Cả hai - trong bối cảnh của Oracle - những sai lầm lớn, sẽ dẫn đến sao chép dữ liệu, dữ liệu mồ côi và do đó: tham nhũng dữ liệu. Tôi không thể tưởng tượng một cơ sở dữ liệu mà không có FK thi hành. Có vẻ như hỗn loạn với tôi. Nó hơi giống với hệ thống cấp phép Unix: hãy tưởng tượng rằng mọi người đều đã root. Hãy nghĩ về sự hỗn loạn.

Khóa ngoại là rất cần thiết, giống như Khóa chính. Nó giống như nói: nếu chúng ta loại bỏ Khóa chính thì sao? Vâng, sự hỗn loạn hoàn toàn sẽ xảy ra. Đó là những gì. Bạn không được chuyển trách nhiệm chính hoặc khóa ngoại sang cấp lập trình, nó phải ở cấp dữ liệu.

Hạn chế? Chắc chắn rồi ! Bởi vì khi chèn, rất nhiều kiểm tra sẽ xảy ra. Nhưng, nếu tính toàn vẹn dữ liệu quan trọng hơn hiệu suất, thì đó là điều không có trí tuệ. Vấn đề với hiệu suất trên Oracle liên quan nhiều hơn đến các chỉ mục, đi kèm với PK và FK.

2
tvCa

Họ có thể làm cho việc xóa các bản ghi trở nên cồng kềnh hơn - bạn không thể xóa bản ghi "chính" trong đó có các bản ghi trong các bảng khác nơi các khóa ngoại sẽ vi phạm ràng buộc đó. Bạn có thể sử dụng kích hoạt để xóa tầng.

Nếu bạn chọn khóa chính của mình một cách không chính xác, thì việc thay đổi giá trị đó càng trở nên phức tạp hơn. Ví dụ: nếu tôi có PK của bảng "khách hàng" của mình làm tên của người đó và biến khóa đó thành FK trong bảng "đơn hàng", nếu khách hàng muốn đổi tên, thì đó là một nỗi đau hoàng gia .. Nhưng đó chỉ là thiết kế cơ sở dữ liệu kém chất lượng.

Tôi tin rằng những lợi thế trong việc sử dụng các phím fireign vượt trội hơn bất kỳ nhược điểm nào được cho là.

1
Ken Ray

Tôi phải thứ hai hầu hết các ý kiến ​​ở đây, Khóa ngoại là các mục cần thiết để đảm bảo rằng bạn có dữ liệu với tính toàn vẹn. Các tùy chọn khác nhau cho BẬT XÓA và CẬP NHẬT sẽ cho phép bạn khắc phục một số "sự cố" mà mọi người đề cập ở đây liên quan đến việc sử dụng chúng.

Tôi thấy rằng trong 99% tất cả các dự án của mình, tôi sẽ có FK để thực thi tính toàn vẹn của dữ liệu, tuy nhiên, có những lần hiếm hoi tôi có khách hàng PHẢI giữ dữ liệu cũ của họ, bất kể nó tệ đến mức nào .... nhưng sau đó tôi dành rất nhiều thời gian để viết mã đi vào để chỉ nhận được dữ liệu hợp lệ, vì vậy nó trở nên vô nghĩa.

1
Mitchel Sellers

Lập luận tôi đã nghe là front-end nên có các quy tắc kinh doanh này. Khóa ngoại "thêm chi phí không cần thiết" khi bạn không nên cho phép bất kỳ thao tác chèn nào phá vỡ các ràng buộc của bạn ở vị trí đầu tiên. Tôi có đồng ý với điều này không? Không, nhưng đó là những gì tôi đã luôn luôn nghe.

EDIT : Tôi đoán là anh ấy đã đề cập đến các ràng buộc khóa ngoài , không phải là khóa ngoài như một khái niệm.

1
lordscarlet

Việc xác minh các ràng buộc khóa ngoài cần một chút thời gian của CPU, vì vậy một số người bỏ qua các khóa ngoại để có thêm hiệu năng.

1
remonedo

Nếu bạn chắc chắn tuyệt đối, rằng một hệ thống cơ sở dữ liệu cơ bản sẽ không thay đổi trong tương lai, tôi sẽ sử dụng các khóa ngoại để đảm bảo tính toàn vẹn dữ liệu.

Nhưng đây là một lý do thực tế rất tốt khác để không sử dụng khóa ngoại nào cả :

Bạn đang phát triển một sản phẩm, cần hỗ trợ các hệ thống cơ sở dữ liệu khác nhau.

Nếu bạn đang làm việc với Entity Framework, có thể kết nối với nhiều hệ thống cơ sở dữ liệu khác nhau, bạn cũng có thể muốn hỗ trợ cơ sở dữ liệu máy chủ "miễn phí mã nguồn mở". Không phải tất cả các cơ sở dữ liệu này có thể hỗ trợ các quy tắc khóa ngoài của bạn (cập nhật, xóa các hàng ...).

Điều này có thể dẫn đến các vấn đề khác nhau :

1.) Bạn có thể gặp lỗi, khi cấu trúc cơ sở dữ liệu được tạo hoặc cập nhật. Có thể sẽ chỉ có các lỗi im lặng, bởi vì các khóa ngoại của bạn bị hệ thống cơ sở dữ liệu bỏ qua.

2.) Nếu bạn dựa vào khóa ngoại, bạn sẽ có thể thực hiện ít hơn hoặc thậm chí không kiểm tra tính toàn vẹn dữ liệu trong logic kinh doanh của bạn. Bây giờ, nếu hệ thống cơ sở dữ liệu mới không hỗ trợ các quy tắc khóa ngoài này hoặc chỉ hành xử theo một cách khác, bạn phải viết lại logic nghiệp vụ của mình.

Bạn có thể hỏi: Ai cần các hệ thống cơ sở dữ liệu khác nhau? Chà, không phải ai cũng có đủ khả năng hoặc muốn có một SQL-Server toàn diện trên máy của mình. Đây là phần mềm, cần được duy trì. Những người khác đã đầu tư thời gian và tiền bạc vào một số hệ thống DB khác. Cơ sở dữ liệu không có máy chủ rất tốt cho các khách hàng nhỏ chỉ trên một máy.

Không ai biết, tất cả các hệ thống DB này hoạt động như thế nào, nhưng logic kinh doanh của bạn, với các kiểm tra tính toàn vẹn, luôn giữ nguyên.

1
Michael

Tôi lặp lại câu trả lời của Dmitriy - rất tốt.

Đối với những người lo lắng về chi phí hiệu năng mà FK thường mang lại, có một cách (trong Oracle), bạn có thể có được lợi thế tối ưu hóa truy vấn của ràng buộc FK mà không cần chi phí xác thực ràng buộc trong quá trình chèn, xóa hoặc cập nhật. Đó là tạo ra ràng buộc FK với các thuộc tính LIÊN QUAN ĐẾN NOVALIDATE. Điều này có nghĩa là trình tối ưu hóa truy vấn ASSUMES rằng ràng buộc đã được thi hành khi xây dựng các truy vấn, mà không có cơ sở dữ liệu thực sự thực thi ràng buộc. Bạn phải rất cẩn thận ở đây để chịu trách nhiệm khi bạn điền vào bảng có ràng buộc FK như thế này để đảm bảo chắc chắn rằng bạn không có dữ liệu trong (các) cột FK vi phạm ràng buộc đó, như thể bạn làm như vậy có thể nhận được kết quả không đáng tin cậy từ các truy vấn liên quan đến bảng ràng buộc FK này.

Tôi thường sử dụng chiến lược này trên một số bảng trong lược đồ mart dữ liệu của mình, nhưng không phải trong lược đồ phân tầng tích hợp. Tôi chắc chắn rằng các bảng tôi đang sao chép dữ liệu từ đó đã có cùng một ràng buộc được thi hành hoặc thường trình ETL thực thi ràng buộc đó.

1
Mike McAllister

Tôi cũng đã nghe lập luận này - từ những người quên đặt chỉ mục vào khóa ngoại của họ và sau đó phàn nàn rằng các hoạt động nhất định là chậm (vì kiểm tra ràng buộc có thể tận dụng bất kỳ chỉ mục nào). Vì vậy, để tóm tắt: Không có lý do chính đáng để không sử dụng khóa ngoại. Tất cả các cơ sở dữ liệu hiện đại đều hỗ trợ xóa tầng, vì vậy ...

1
Arno

Đối với tôi, nếu bạn muốn tuân theo các tiêu chuẩn ACID , điều quan trọng là phải có khóa ngoại để đảm bảo tính toàn vẹn tham chiếu.

1
CodeRot

Nhiều người trả lời ở đây quá nôn nao về tầm quan trọng của tính toàn vẹn tham chiếu được thực hiện thông qua các ràng buộc tham chiếu. Làm việc trên các cơ sở dữ liệu lớn với tính toàn vẹn tham chiếu chỉ không hoạt động tốt. Oracle có vẻ đặc biệt tệ trong việc xóa tầng. Nguyên tắc nhỏ của tôi là các ứng dụng không bao giờ nên cập nhật cơ sở dữ liệu trực tiếp và phải thông qua một thủ tục được lưu trữ. Điều này giữ cơ sở mã bên trong cơ sở dữ liệu và có nghĩa là cơ sở dữ liệu duy trì tính toàn vẹn của nó.

Khi nhiều ứng dụng có thể truy cập vào cơ sở dữ liệu, các vấn đề sẽ phát sinh do các ràng buộc toàn vẹn tham chiếu nhưng điều này nằm trong tầm kiểm soát.

Có một vấn đề rộng lớn hơn ở chỗ, các nhà phát triển ứng dụng có thể có những yêu cầu rất khác nhau mà các nhà phát triển cơ sở dữ liệu có thể không nhất thiết phải quen thuộc.

1
Zak

Tôi cũng nghĩ rằng khóa ngoại là cần thiết trong hầu hết các cơ sở dữ liệu. Hạn chế duy nhất (bên cạnh hiệu năng đạt được khi có tính nhất quán bắt buộc) là có khóa ngoại cho phép mọi người viết mã giả sử có khóa ngoại chức năng. Điều đó không bao giờ nên được cho phép.

Ví dụ: tôi đã thấy mọi người viết mã chèn vào bảng được tham chiếu và sau đó thử chèn vào bảng tham chiếu mà không xác minh lần chèn đầu tiên đã thành công. Nếu khóa ngoại được xóa sau đó, điều đó dẫn đến cơ sở dữ liệu không nhất quán.

Bạn cũng không có tùy chọn giả định một hành vi cụ thể về cập nhật hoặc xóa. Bạn vẫn cần phải viết mã của bạn để làm những gì bạn muốn bất kể có khóa ngoại không. Nếu bạn cho rằng việc xóa được xếp tầng khi không, việc xóa của bạn sẽ thất bại. Nếu bạn cho rằng các cập nhật cho các cột được tham chiếu được hỗ trợ cho các hàng tham chiếu khi chúng không có, các cập nhật của bạn sẽ thất bại. Đối với mục đích viết mã, bạn cũng có thể không có các tính năng đó.

Nếu các tính năng đó được bật, thì mã của bạn sẽ mô phỏng chúng bằng mọi cách và bạn sẽ mất một chút hiệu suất.

Vì vậy, tóm tắt .... Khóa ngoại là rất cần thiết nếu bạn cần một cơ sở dữ liệu nhất quán. Khóa ngoại không bao giờ được coi là có mặt hoặc có chức năng trong mã mà bạn viết.

1
Eric

Wowowo ...
[.__.] Câu trả lời ở khắp mọi nơi. Thật ra đây là chủ đề phức tạp nhất mà tôi từng gặp. Tôi sử dụng FK khi cần nhưng trên môi trường sản xuất tôi hiếm khi sử dụng chúng.

[.__.] Đây là lý do tôi hiếm khi sử dụng Fks:

[.__.] 1. Hầu hết thời gian tôi đang xử lý dữ liệu khổng lồ trên máy chủ nhỏ để cải thiện hiệu suất, tôi cần loại bỏ FK. Bởi vì khi bạn có FK và bạn thực hiện Tạo, Cập nhật hoặc Xóa RDBMS trước tiên, hãy kiểm tra xem có vi phạm ràng buộc nào không và nếu bạn có DB lớn có thể gây tử vong

[.__.] 2. Đôi khi tôi cần nhập dữ liệu từ những nơi khác và vì tôi không chắc chắn về cấu trúc của chúng, tôi chỉ cần bỏ FK.

[.__.] 3. Trong trường hợp bạn đang xử lý nhiều DB và có khóa tham chiếu trong một DB khác sẽ không hoạt động tốt (như bây giờ) cho đến khi bạn loại bỏ FK (quan hệ cơ sở dữ liệu chéo)
4. Chúng cũng là một trường hợp khi bạn viết một ứng dụng sẽ dựa trên bất kỳ RDBMS nào hoặc bạn muốn DB của mình được xuất và nhập trong bất kỳ hệ thống RDBMS nào trong trường hợp này, mỗi hệ thống RDBMS cụ thể có cách xử lý FK riêng và bạn có thể sẽ bắt buộc phải bỏ việc sử dụng FK.

[.__.] 5. Nếu bạn sử dụng nền tảng RDBMS (ORM), bạn biết rằng một số trong số họ cung cấp ánh xạ của riêng họ tùy thuộc vào giải pháp và tính kỹ thuật mà họ cung cấp và bạn không quan tâm đến việc tạo các bảng và FK của họ.

[.__.] 6. Trước điểm cuối cùng sẽ là kiến ​​thức để đối phó với DB có FK và kiến ​​thức để viết một ứng dụng thực hiện tất cả Công việc mà không cần FK 7. Cuối cùng, khi tôi bắt đầu nói tất cả phụ thuộc vào kịch bản của bạn, trong trường hợp kiến ​​thức không phải là một rào cản. Bạn sẽ luôn muốn chạy tốt nhất trong số tốt nhất bạn có thể nhận được!


Cám ơn mọi người!

Một lần khi FK có thể gây ra sự cố cho bạn là khi bạn có dữ liệu lịch sử tham chiếu khóa (trong bảng tra cứu) mặc dù bạn không còn muốn khóa đó nữa.
[.__.] Rõ ràng giải pháp là thiết kế mọi thứ tốt hơn trước, nhưng tôi đang nghĩ đến các tình huống trong thế giới thực ở đây nơi bạn không luôn kiểm soát được giải pháp đầy đủ.
[.__.] Ví dụ: có lẽ bạn có bảng tra cứu customer_type liệt kê các loại khách hàng khác nhau - giả sử bạn cần xóa một loại khách hàng nhất định, nhưng (do hạn chế kinh doanh) không thể cập nhật phần mềm máy khách và không ai phát hiện ra tình huống này khi phát triển phần mềm, thực tế đó là khóa ngoại trong một số bảng khác có thể ngăn bạn xóa hàng ngay cả khi bạn biết dữ liệu lịch sử tham chiếu đến nó không liên quan.
[.__.] Sau khi bị đốt cháy với điều này một vài lần, bạn có thể tránh xa việc thực thi các mối quan hệ db.
[.__.] (Tôi không nói điều này là tốt - chỉ cần đưa ra lý do tại sao bạn có thể quyết định tránh các hạn chế FK và db nói chung)

0
hamishmcn

Trong một dự án tôi đã làm việc thường có các mối quan hệ ngầm chứ không phải rõ ràng để có thể nối nhiều bảng trên cùng một cột.

Lấy bảng sau

Địa chỉ

  • Địa chỉId (PK)
  • ID phap nhân
  • EntityType
  • Thành phố
  • Tiểu bang
  • Quốc gia
  • Vân vân..

Các giá trị có thể có của EntityType có thể là Nhân viên, Công ty, Khách hàng và EntityId đề cập đến khóa nguyên thủy của bất kỳ bảng nào bạn quan tâm.

Tôi thực sự không nghĩ rằng đây là cách tốt nhất để làm mọi thứ, nhưng nó đã làm việc cho dự án này.

0
Curtis

Giống như nhiều thứ, đó là một sự đánh đổi. Đó là câu hỏi về nơi bạn muốn thực hiện công việc để xác minh tính toàn vẹn dữ liệu:

(1) sử dụng khóa ngoại (một điểm duy nhất để định cấu hình cho bảng, tính năng đã được triển khai, thử nghiệm, được chứng minh là hoạt động)

(2) để lại cho người dùng cơ sở dữ liệu (có thể nhiều người dùng/ứng dụng cập nhật cùng một bảng có nghĩa là nhiều điểm tiềm năng hơn của sự thất bại và tăng độ phức tạp trong thử nghiệm).

Cơ sở dữ liệu sẽ hiệu quả hơn (2), dễ bảo trì hơn và ít rủi ro hơn với (1).

0
Jen A

Tôi sẽ lặp lại những gì Dmitriy nói, nhưng thêm vào một điểm.

Tôi đã làm việc trên một hệ thống thanh toán hàng loạt cần chèn các nhóm hàng lớn trên 30 bảng. Chúng tôi không được phép thực hiện một máy bơm dữ liệu (Oracle) vì vậy chúng tôi phải thực hiện chèn số lượng lớn. Những cái bàn đó có khóa ngoại, nhưng chúng tôi đã đảm bảo rằng chúng không phá vỡ bất kỳ mối quan hệ nào.

Trước khi chèn, chúng tôi vô hiệu hóa các ràng buộc khóa ngoài để Oracle không mất công thực hiện việc chèn. Sau khi chèn thành công, chúng tôi kích hoạt lại các ràng buộc.

PS: Trong một cơ sở dữ liệu lớn có nhiều khóa ngoại và dữ liệu hàng con cho một bản ghi, đôi khi các khóa ngoại có thể xấu và bạn có thể không cho phép xóa tầng. Đối với chúng tôi trong hệ thống thanh toán, sẽ mất quá nhiều thời gian và quá đánh thuế vào cơ sở dữ liệu nếu chúng tôi thực hiện xóa tầng, vì vậy chúng tôi chỉ đánh dấu bản ghi là xấu với trường trên bảng điều khiển chính (phụ huynh).

0
typicalrunt

Trong DB2, nếu các MQT (Bảng truy vấn cụ thể hóa) được sử dụng, các ràng buộc khóa ngoài được yêu cầu cho trình tối ưu hóa để chọn kế hoạch phù hợp cho bất kỳ truy vấn nào. Vì chúng chứa thông tin về cardinality, trình tối ưu hóa sử dụng siêu dữ liệu rất nhiều để sử dụng MQT hay không.

0
Senthil

Một nguyên tắc tốt của thiết kế cấu trúc dữ liệu là đảm bảo rằng mọi thuộc tính của bảng hoặc đối tượng phải chịu một ràng buộc được hiểu rõ. Điều này rất quan trọng vì nếu bạn hoặc chương trình của bạn có thể tin tưởng vào dữ liệu hợp lệ trong cơ sở dữ liệu, bạn sẽ ít gặp lỗi chương trình do dữ liệu xấu gây ra. Bạn cũng dành ít thời gian hơn để viết mã để xử lý các điều kiện lỗi và bạn có nhiều khả năng viết mã xử lý lỗi lên phía trước.

Trong nhiều trường hợp, các ràng buộc này có thể được xác định tại thời gian biên dịch, trong trường hợp đó bạn có thể viết bộ lọc để đảm bảo rằng thuộc tính luôn nằm trong phạm vi hoặc cố gắng lưu thuộc tính không thành công.

Tuy nhiên, trong nhiều trường hợp, các ràng buộc này có thể thay đổi trong thời gian chạy. Ví dụ: bạn có thể có một bảng "ô tô" có "màu" là thuộc tính ban đầu có các giá trị, ví dụ: "đỏ", "xanh" và "xanh". Có thể trong quá trình thực thi chương trình để thêm các màu hợp lệ vào danh sách ban đầu đó và các "ô tô" mới được thêm vào có thể có bất kỳ màu nào trong danh sách màu cập nhật. Hơn nữa, bạn thường muốn danh sách màu được cập nhật này để tồn tại khi khởi động lại chương trình.

Để trả lời câu hỏi của bạn, hóa ra nếu bạn có yêu cầu về ràng buộc dữ liệu có thể thay đổi trong thời gian chạy và những thay đổi đó phải tồn tại khi khởi động lại chương trình, khóa ngoại là giải pháp đơn giản và ngắn gọn nhất cho vấn đề. Chi phí phát triển là việc thêm một bảng (ví dụ: "màu sắc", ràng buộc khóa ngoại đối với bảng "ô tô" và chỉ mục) và chi phí thời gian chạy là tra cứu bảng bổ sung cho các màu cập nhật để xác thực dữ liệu và chi phí thời gian chạy này thường được giảm thiểu bằng cách lập chỉ mục và lưu vào bộ đệm.

Nếu bạn không sử dụng khóa ngoại cho các yêu cầu này, bạn phải viết phần mềm để quản lý danh sách, xem các mục hợp lệ, lưu vào đĩa, cấu trúc dữ liệu hiệu quả nếu danh sách lớn, đảm bảo rằng mọi cập nhật vào danh sách không làm hỏng tệp danh sách, cung cấp quyền truy cập nối tiếp vào danh sách trong trường hợp có nhiều người đọc và/hoặc người viết, v.v. tức là bạn cần triển khai nhiều chức năng RDBMS.

0
Jay Godse

Tôi luôn nghĩ rằng thật lười biếng khi không sử dụng chúng. Tôi đã được dạy nó nên luôn luôn được thực hiện. Nhưng sau đó, tôi không nghe cuộc thảo luận của Joel. Anh ta có thể có một lý do tốt, tôi không biết.

0
Kilhoffer

Q uite thường chúng tôi nhận được các lỗi với ràng buộc FK Không thể thêm hoặc cập nhật một hàng con: một ràng buộc khóa ngoại không thành công Giả sử có hai bảng Invent_source và Contract_lines, và chúng tôi đang giới thiệu Invent_source_id trong hợp đồng_lines từ Invent_source và giả sử chúng tôi muốn xóa bản ghi khỏi Invent_source và bản ghi đã có trong hợp đồng hoặc chúng tôi muốn xóa cột PK từ bảng Cơ sở, chúng tôi gặp lỗi cho các ràng buộc FK, chúng tôi có thể tránh được bằng cách sử dụng các bước được ghi dưới đây.

CREATE TABLE inventory_source (
inventory_source_id int(11) NOT NULL AUTO_INCREMENT,
display_name varchar(40) NOT NULL,
state_id int(11) NOT NULL,
PRIMARY KEY (inventory_source_id),
KEY state_id (state_id),
CONSTRAINT ba_inventory_source_state_fk FOREIGN KEY (state_id) REFERENCES   ba_state (state_id)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

CREATE TABLE contract_lines(
contract_line_id int(11) NOT NULL AUTO_INCREMENT,
inventory_source_id int(11) NULL ,
PRIMARY KEY (contract_line_id),
UNIQUE KEY contract_line_id (contract_line_id),
KEY AI_contract_line_id (contract_line_id),
KEY contract_lines_inventory_source_fk (inventory_source_id),
CONSTRAINT contract_lines_inventory_source_fk FOREIGN KEY       (inventory_source_id) REFERENCES ba_inventory_source (inventory_source_id)
) ENGINE=InnoDB AUTO_INCREMENT=135 DEFAULT CHARSET=utf8 ;

Chúng tôi có thể khắc phục bằng các bước sau: -

  1. Xóa hoặc cập nhật hàng từ Invent_source sẽ tự động xóa hoặc cập nhật các hàng khớp trong bảng hợp đồng và điều này được gọi là xóa tầng hoặc cập nhật.
  2. Một cách khác để làm điều đó là đặt cột i.e Invent_source_id trong bảng hợp đồng_lines thành NULL, khi một bản ghi tương ứng với nó bị xóa trong bảng Invent_source.
  3. Chúng ta có thể hạn chế bảng cha để xóa hoặc cập nhật theo cách khác, người ta có thể từ chối thao tác xóa hoặc cập nhật cho bảng Invent_source.
  4. Cố gắng xóa hoặc cập nhật giá trị khóa chính sẽ không được phép tiến hành nếu có giá trị khóa ngoại liên quan trong bảng được tham chiếu.
0
Vikas Kukreti