Có ổn không khi có khóa ngoại làm khóa chính?


102

Tôi có hai bảng:

  • Người dùng (tên người dùng, mật khẩu)
  • Hồ sơ (profileId, giới tính, ngày sinh, ...)

Hiện tại tôi đang sử dụng phương pháp này: mỗi bản ghi Hồ sơ có một trường có tên "userId" làm khóa ngoại liên kết đến bảng Người dùng. Khi người dùng đăng ký, bản ghi Hồ sơ của anh ta sẽ tự động được tạo.

Tôi đang bối rối với một người bạn gợi ý của tôi: phải có "userId" lĩnh vực như nước ngoàichính chìa khóa và xóa các "profileId" lĩnh vực. Cách tiếp cận nào tốt hơn?


3
Entity Framework tạo ra điều đó (với mã đầu tiên) cho quan hệ zeroOrOne (và một) -to-một. Vì vậy, ... nó có thể. Đó có phải là cách tốt nhất ... Đó là một câu hỏi khác. Nhưng nó hợp lệ. Tôi chưa bao giờ làm điều đó trong khi tạo cơ sở dữ liệu của riêng mình (nhưng tôi thậm chí chưa bao giờ nghĩ đến điều đó).
Raphaël Althaus

Câu trả lời:


132

Các khóa ngoại hầu như luôn luôn là "Cho phép trùng lặp", điều này sẽ khiến chúng không phù hợp làm Khóa chính.

Thay vào đó, hãy tìm một trường xác định duy nhất từng bản ghi trong bảng hoặc thêm trường mới (số nguyên tự động tăng dần hoặc GUID) để hoạt động như khóa chính.

Ngoại lệ duy nhất này là bảng với một one-to-one mối quan hệ, nơi nước ngoài chủ chốt và chính chủ chốt của bảng liên kết là một và giống nhau.


73
Một khóa chính tổng hợp bao gồm hai khóa ngoại cũng hoàn toàn phù hợp để triển khai các mối quan hệ nhiều-nhiều.
sang phải

1
@rezadru: Tôi không đồng ý với rightfold, nhưng khóa thay thế hầu như luôn là lựa chọn tốt hơn.
Robert Harvey

4
Không có gì về khóa ngoại quy định rằng nó là 1 đến nhiều (hoặc "cho phép trùng lặp" như đã viết). Ràng buộc chính và tính duy nhất là hai khái niệm riêng biệt trong cơ sở dữ liệu và có thể dễ dàng trộn lẫn dễ dàng như thêm một chỉ mục (sẽ là một khái niệm riêng biệt thứ ba).
Blindguy

40

Các khóa chính luôn cần phải là duy nhất, các khóa ngoại cần cho phép các giá trị không phải là duy nhất nếu bảng là mối quan hệ một-nhiều. Bạn hoàn toàn có thể sử dụng khóa ngoại làm khóa chính nếu bảng được kết nối theo mối quan hệ một-một, không phải một-nhiều. Nếu bạn muốn cùng một bản ghi người dùng có khả năng có nhiều hơn 1 bản ghi hồ sơ liên quan, hãy sử dụng khóa chính riêng biệt, nếu không, hãy gắn với những gì bạn có.


11

Có, khóa chính là khóa ngoại là hợp pháp. Đây là một cấu trúc hiếm, nhưng nó áp dụng cho:

  • quan hệ 1: 1. Hai bảng không thể được hợp nhất thành một vì các quyền và đặc quyền khác nhau chỉ áp dụng ở cấp bảng (kể từ năm 2017, cơ sở dữ liệu như vậy sẽ là kỳ lạ).

  • quan hệ 1: 0..1. Hồ sơ có thể tồn tại hoặc không, tùy thuộc vào kiểu người dùng.

  • hiệu suất là một vấn đề và thiết kế hoạt động như một phân vùng: bảng hồ sơ hiếm khi được truy cập, được lưu trữ trên một đĩa riêng hoặc có chính sách sharding khác so với bảng người dùng. Sẽ không có ý nghĩa nếu bộ nhớ gạch dưới là cột.


Sẽ có một hiệu suất tiêu cực nếu các bảng được nối với nhau thường xuyên, dẫn đến khuyến nghị thông thường rằng 1 bảng tốt hơn. Trong một số trường hợp, dữ liệu luôn được truy cập riêng biệt, không được kết hợp và có thể có lợi ích về mặt tổ chức khi có hai bảng với mối quan hệ 1: 1.
Blindguy

4

Thường được coi là thực hành xấu khi có một mối quan hệ 1-1. Điều này là do bạn chỉ có thể có dữ liệu được đại diện trong một bảng và đạt được kết quả tương tự.

Tuy nhiên, có những trường hợp bạn không thể thực hiện những thay đổi này đối với bảng bạn đang tham chiếu. Trong trường hợp này, không có vấn đề gì khi sử dụng Khóa ngoại làm khóa chính. Có thể hữu ích khi có một khóa tổng hợp bao gồm khóa chính duy nhất tự động tăng dần và khóa ngoại.

Tôi hiện đang làm việc trên một hệ thống nơi người dùng có thể đăng nhập và tạo mã đăng ký để sử dụng với một ứng dụng. Vì lý do tôi sẽ không đi sâu vào, tôi không thể chỉ cần thêm các cột cần thiết vào bảng người dùng. Vì vậy, tôi đang đi xuống một tuyến đường với bảng mã.


2
Tôi hầu như đồng ý với bạn rằng có nhiều lợi ích khi có tất cả dữ liệu trong cùng một bảng dưới dạng các cột bổ sung. Mặc dù wrt this .. "bạn chỉ có thể có dữ liệu được đại diện trong một bảng và đạt được cùng một kết quả" ..: có một bảng riêng biệt có thể hữu ích, ví dụ: ở đây nếu mục nhập bảng hồ sơ là tùy chọn. Ví dụ: mọi khách hàng của ngân hàng có thể không có đăng ký ngân hàng trực tuyến. Trong trường hợp đó, bảng đăng ký IB có thể được sử dụng để hạn chế các bảng khác có thêm các bản ghi con. Một lần nữa, ở đây nó cũng có thể được thực hiện với PK mới cho bảng đăng ký IB.
Teddy

1
@Teddy Tương tự như vậy, tôi hầu như đồng ý với những gì bạn nói. Tuy nhiên, trong câu hỏi ban đầu, họ nêu "... hồ sơ Tiểu sử của anh ấy được tạo tự động ..." ngụ ý rằng bảng Tiểu sử không phải là tùy chọn. Trong tình huống mà bảng hồ sơ là tùy chọn thì việc có nó như một bảng riêng là có thể thực hiện được. Nhưng một lần nữa, họ chỉ có thể sử dụng các cột có thể nullable trong cùng một bảng.
Tshsmith

1
Sử dụng một bảng thứ hai riêng biệt, chúng tôi có thể ngăn mục nhập trong bảng thứ ba chỉ được phép cho những người có mục nhập trong bảng thứ hai.
Teddy

Hoàn toàn có thể, nhưng nếu chúng ta hợp nhất các bảng 1 với 1, chúng ta có thể ngăn những người có giá trị null truy cập vào bảng thứ ba (về mặt kỹ thuật là thứ hai bây giờ). Nhưng câu hỏi mà OP hỏi có dòng "... khi đăng ký .. ... hồ sơ của anh ấy được tự động tạo ...", khiến điều này trở nên thừa.
Tshsmith

Lý do chính của tôi để xem xét điều này là trong kho dữ liệu, thực hành tốt là tách bảng dữ liệu và bảng thứ nguyên. Bảng dữ liệu và kích thước riêng biệt là những gợi ý hữu ích khi làm việc với phần mềm như PowerPivot, PowerBI và Tableau.
Marco Rosas

4

Có, khóa ngoại có thể là khóa chính trong trường hợp có mối quan hệ 1-1 giữa các bảng đó


2
điều này cũng hữu ích cho thiết kế supertype-subtype. Khóa chính của bảng kiểu con phải là khóa ngoại tham chiếu đến bảng siêu kiểu.
axelioo

2

Đúng ra tôi không nên làm vậy. Tôi sẽ giữprofileID làm khóa chính của bảngProfile

Khóa ngoại chỉ là một ràng buộc tham chiếu giữa hai bảng

Người ta có thể tranh luận rằng một khóa chính là cần thiết như mục tiêu của bất kỳ khóa ngoại nào tham chiếu đến nó từ các bảng khác. Khóa ngoại là một tập hợp một hoặc nhiều cột trong bất kỳ bảng nào (không nhất thiết phải là khóa ứng viên, chưa nói đến khóa chính, của bảng đó) có thể chứa (các) giá trị được tìm thấy trong (các) cột khóa chính của một số bảng khác. Vì vậy chúng ta phải có khóa chính để khớp với khóa ngoại. Hay chúng ta phải? Mục đích duy nhất của khóa chính trong cặp khóa chính / khóa ngoại là cung cấp một phép nối rõ ràng - để duy trì tính toàn vẹn của tham chiếu đối với bảng "ngoại" chứa khóa chính được tham chiếu. Điều này đảm bảo rằng giá trị mà khóa ngoại tham chiếu đến sẽ luôn hợp lệ (hoặc null, nếu được phép).

http://www.aisintl.com/case/primary_and_foreign_key.html


1
Có thể - nếu bạn có ràng buộc FK giữa User.UserID và Profile.UserID, thì bạn nên có một chỉ mục trên Profile.UserID. Tại sao không tạo chỉ mục nhóm chính trên Hồ sơ bảng, tiết kiệm chỉ mục thứ hai và rất nhiều công việc không cần thiết cho cơ sở dữ liệu?
Kỹ sư đảo ngược

1

Nó phụ thuộc vào doanh nghiệp và hệ thống.

Nếu userId của bạn là duy nhất và luôn là duy nhất, bạn có thể sử dụng userId làm khóa chính của mình. Nhưng nếu bạn muốn mở rộng hệ thống của mình, điều đó sẽ khiến mọi thứ trở nên khó khăn. Tôi khuyên bạn nên thêm khóa ngoại trong người dùng bảng để tạo mối quan hệ với cấu hình bảng thay vì thêm khóa ngoại trong cấu hình bảng.


0

Câu trả lời ngắn gọn: DEPENDS .... Trong trường hợp cụ thể này, nó có thể ổn. Tuy nhiên, các chuyên gia sẽ khuyến cáo không nên sử dụng nó bất cứ lúc nào; kể cả trường hợp của bạn.

Tại sao?

Các khóa hiếm khi là duy nhất trong bảng khi chúng ngoại lai (bắt nguồn từ bảng khác) với bảng được đề cập. Ví dụ: một ID mặt hàng có thể là duy nhất trong bảng ITEMS, nhưng không phải trong bảng ĐƠN HÀNG, vì cùng một loại mặt hàng rất có thể sẽ tồn tại trong một đơn đặt hàng khác. Tương tự như vậy, ID đơn hàng có thể là duy nhất (có thể) trong bảng ORDERS, nhưng không phải trong một số bảng khác như ORDER_DETAILS, nơi một đơn hàng có nhiều mục hàng có thể tồn tại và để truy vấn một mục cụ thể trong một đơn hàng cụ thể, bạn cần kết hợp hai FK (order_id và item_id) làm PK cho bảng này.

Tôi không phải là chuyên gia DB, nhưng nếu bạn có thể biện minh một cách hợp lý để có một giá trị được tạo tự động làm PK của bạn, tôi sẽ làm điều đó. Nếu điều này không thực tế, thì sự kết hợp của hai (hoặc có thể nhiều hơn) FK có thể đóng vai trò là PK của bạn. NHƯNG, tôi không thể nghĩ ra bất kỳ trường hợp nào mà một giá trị FK duy nhất có thể được coi là PK.

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.