2009-09-05 37 views
18

Tôi đang làm việc trên thiết kế của cơ sở dữ liệu sẽ được sử dụng để lưu trữ dữ liệu bắt nguồn từ một số nguồn khác nhau. Các cá thể tôi đang lưu trữ được gán các ID duy nhất bởi các nguồn gốc. Mỗi cá thể tôi lưu trữ phải chứa thông tin về nguồn mà nó xuất phát cùng với ID được liên kết bởi nguồn này.Phím chính tổng hợp

Như một ví dụ, hãy xem xét bảng sau minh họa các vấn đề:

---------------------------------------------------------------- 
| source_id | id_on_source | data        | 
---------------------------------------------------------------- 
| 1   | 17600  | ...        | 
| 1   | 17601  | ...        | 
| 2   | 1   | ...        | 
| 3   | 1   | ...        | 
---------------------------------------------------------------- 

Lưu ý rằng trong khi id_on_source là duy nhất cho mỗi nguồn, người ta có thể cho cùng id_on_source được tìm thấy cho các nguồn khác nhau.

Tôi hiểu rõ về cơ sở dữ liệu quan hệ, nhưng không xa chuyên gia hoặc thậm chí là người dùng có kinh nghiệm. Vấn đề tôi phải đối mặt với thiết kế này là những gì tôi nên sử dụng làm khóa chính. Dữ liệu dường như chỉ ra việc sử dụng khóa chính kết hợp của (source_id, id_on_source). Sau một chút googling tôi tìm thấy một số cuộc tranh luận nóng về những ưu và khuyết điểm của khóa chính composite, tuy nhiên, để lại cho tôi một chút bối rối.

Bảng sẽ có mối quan hệ một-nhiều với các bảng khác và do đó sẽ được đề cập đến trong khóa ngoại của các bảng khác.

Tôi không gắn với một số cụ thể RDBMS và tôi không chắc chắn nếu nó quan trọng vì lợi ích của đối số, nhưng giả sử tôi thích làm việc với SQLiteMySQL.

Ưu và nhược điểm của việc sử dụng khóa tổng hợp ngoài trong trường hợp này là gì? Bạn thích cái nào?

Trả lời

26

Cá nhân tôi tìm thấy các khóa chính kết hợp để gây đau. Đối với mỗi bảng mà bạn muốn tham gia vào bảng "nguồn" của bạn, bạn sẽ cần thêm cả trường source_id và id_on_source.

Tôi sẽ tạo khóa chính tăng tự động chuẩn trên bảng nguồn của bạn và thêm chỉ mục duy nhất trên cột source_id và id_on_source.

Điều này sau đó cho phép bạn chỉ thêm id của bảng nguồn làm khóa ngoại trên các bảng khác.

Nói chung tôi cũng đã tìm thấy hỗ trợ cho các phím composite tiểu học trong nhiều khuôn khổ và các sản phẩm dụng cụ được "chắp vá" lúc tốt nhất và không tồn tại trong những người khác

+0

Hãy nghĩ về PK tổng hợp để lưu trữ Kỷ nguyên và Dấu thời gian (1, 1970 ~ 2106) (2, 2106 ~ 2242). Bởi vì INT8, INT16, INT32, INT64 là dựa trên nhị phân và có kích thước dựa trên bit thì chúng tôi không có kích thước INT phù hợp cho năm 9999. INT là không đủ và BIG INT quá lớn. – Alix

12

phím composite là khó khăn để quản lý và chậm chạp trong việc tham gia. Vì bạn đang xây dựng bảng tóm tắt, hãy sử dụng khóa thay thế (tức là cột tự động/nhận dạng). Để lại các cột khóa tự nhiên của bạn ở đó.

Điều này cũng có nhiều lợi ích khác. Chủ yếu, nếu bạn hợp nhất với một công ty và họ có một trong các nguồn giống nhau, nhưng các phím được sử dụng lại, bạn sẽ gặp rắc rối nếu bạn không phải là bằng cách sử dụng khóa thay thế.

Đây là thực tiễn tốt nhất được thừa nhận rộng rãi trong kho dữ liệu (một cam kết lớn hơn nhiều so với những gì bạn đang làm, nhưng vẫn có liên quan) và vì lý do chính đáng. Surrogates cung cấp tính toàn vẹn dữ liệu và gia nhập nhanh chóng. Bạn có thể bị đốt rất nhanh bằng các phím tự nhiên, vì vậy hãy tránh xa chúng như một mã định danh và chỉ sử dụng chúng trong quá trình nhập.

+3

Bạn đang nói về vấn đề gì? Nếu bạn có xung đột về hợp nhất, bạn có thể không muốn có lỗi thay vì sao chép dữ liệu không? –

+2

@JeffDavis Chính xác, các khóa thay thế mời dự phòng AFAIK. – nottinhill

+0

Bạn có thể giải thích lý do tại sao các phím tổng hợp bị chậm tham gia? Tôi đang cố gắng hiểu tại sao tôi sẽ không sử dụng các phím tổng hợp thực sự. Nếu tôi có một bảng tham khảo một bảng khác với một khóa tổng hợp (A, B), tôi không thực sự phải tham gia trên toàn bộ pk. Tôi cũng có thể viết 'ON (a.A = another.A) ', phải không? Vì vậy, những gì làm cho điều này chậm hơn? – displayname

1

Một số người khuyên bạn nên sử dụng ID duy nhất toàn cầu (GUID): merge replication and transactional replication with updating subscriptions use uniqueidentifier columns to guarantee that rows are uniquely identified across multiple copies of the table. Nếu giá trị nếu duy nhất trên toàn cầu khi được tạo, thì bạn không cần phải thêm source_id để làm cho nó trở nên duy nhất.


Mặc dù uniqueid là khóa chính tốt, tôi đồng ý tốt hơn nên sử dụng khóa khác, tự nhiên (không nhất thiết phải duy nhất) làm chỉ mục nhóm của bạn. Ví dụ: nếu uniqueid là PK xác định nhân viên, bạn có thể muốn nhóm chỉ mục thành bộ phận (nếu các câu lệnh chọn của bạn thường lấy tất cả nhân viên trong một bộ phận cụ thể). Nếu bạn muốn sử dụng unqiqueid làm chỉ mục nhóm, hãy xem hàm NEWSEQUENTIALID(): điều này tạo ra các giá trị uniqueid tuần tự, mà (được tuần tự) có hiệu suất phân cụm tốt hơn.

+0

chỉ cần cẩn thận (trong SQL Server) ** NOT ** để làm cho khóa chính GUID của bạn khóa cụm của bảng (theo mặc định) - xem bài viết tuyệt vời của Kim Tripp về lý do tại sao không: http: // www. sqlskills.com/BLOGS/KIMBERLY/post/GUIDs-as-PRIMARY-KEYs-andor-the-clustering-key.aspx –

+0

thêm vào câu trả lời của tôi để giải quyết nhận xét đó – ChrisW

+0

Về GUID: Nếu yêu cầu chỉ là có một id cho mỗi bản ghi, có, điều này sẽ làm việc. Nhưng nếu bạn cần biết nguồn là gì, thì bạn phải đăng id nguồn vào bản ghi, hoặc bạn phải có bảng tra cứu ở đâu đó (yuck), hoặc bạn phải tìm kiếm tất cả các nguồn có thể tìm kiếm mà GUID (đôi yuck). Nếu bạn vẫn giữ id nguồn, GUID sẽ không thêm giá trị nào. – Jay

6

Tôi tin rằng các phím tổng hợp tạo ra một mô hình dữ liệu rất tự nhiên và mô tả. Kinh nghiệm của tôi đến từ Oracle và tôi không nghĩ rằng có bất kỳ vấn đề kỹ thuật nào khi tạo một PK tổng hợp. Trong thực tế, bất cứ ai phân tích từ điển dữ liệu sẽ ngay lập tức hiểu điều gì đó về bảng. Trong trường hợp của bạn, rõ ràng là mỗi source_id phải có id_on_source duy nhất.

Việc sử dụng các khóa tự nhiên thường tạo ra một cuộc tranh luận nóng, nhưng những người mà tôi làm việc với các khóa tự nhiên từ góc độ mô hình dữ liệu tốt.

+1

có, nhưng việc tham gia từ một bảng con đến một khóa chính có xu hướng lộn xộn nếu bạn phải tham gia vào hai, ba, bốn điều kiện - và nó bloats khóa chính và do đó tất cả các chỉ số của bạn. Nó có thể cảm thấy tự nhiên, nhưng trong thực tế, nó không phải là một ý tưởng tốt –

+1

điểm chụp. Thông thường bạn sẽ thấy rằng các thực thể chính sẽ có DB tạo ra khóa duy nhất. ví dụ. Bảng khách hàng với CustomerId. Thường có các bảng liên quan thứ cấp của nó có các phím tổng hợp và hầu hết trong số chúng không có FK tham chiếu chúng. ví dụ. nếu bạn lưu trữ lịch sử số điện thoại của khách hàng thì trong bảng Customer_contact_history, các cột CustomerId, điện thoại, thay đổi có thể là tổng hợp PK vì 3 điều này là tự nhiên duy nhất. – softveda

+0

Tôi đang cho bạn một cuộc bỏ phiếu vì tôi đồng ý về nguyên tắc. Nhưng tôi không nghĩ đó là giải pháp tốt nhất trong ví dụ cụ thể này! – Jay

1

Thêm cột ID phụ sẽ khiến bạn phải thực thi HAI ràng buộc duy nhất thay vì một.

Sử dụng cột ID bổ sung đó làm khóa ngoại trong các bảng tham chiếu khác, thay vì khóa tự thể hiện, sẽ khiến bạn phải thực hiện các phép nối KHÁC, cụ thể là trong tất cả các trường hợp bạn cần soruce_ID gốc cộng với ID_on_source cùng với dữ liệu từ bảng tham chiếu.

+0

Bạn có cần thực thi tính duy nhất trong ứng dụng này không? Nếu bạn đang nhận được dữ liệu từ các hệ thống khác, có lẽ đó là vấn đề của họ để thực thi tính duy nhất. Nó trở lại những gì bạn cần để hoàn thành. – Jay

+0

Khi tham gia thêm: Tôi sẽ giữ nguồn và id_on_source trong cùng một bảng, cho dù đó là khóa chính hay không. Tôi không thấy bất kỳ lý do gì ở đây để có một bảng tra cứu thứ hai để làm bản dịch. Giữ tất cả lại với nhau. – Jay

8

Bạn có yêu cầu nghiệp vụ rằng sự kết hợp của hai thuộc tính đó là duy nhất. Vì vậy, bạn nên có một ràng buộc UNIQUE trên hai thuộc tính đó. Cho dù bạn gọi rằng ràng buộc "chính" UNIQUE thực sự chỉ là một sở thích, nó không có nhiều tác động ngoài tài liệu.

Câu hỏi duy nhất là liệu bạn có thêm cột phụ hay không và đánh dấu nó là UNIQUE. Lý do duy nhất tôi có thể thấy để làm điều đó là hiệu suất, đó là một lý do chính đáng.

Cá nhân, tôi không thích cách tiếp cận chuyển từng cơ sở dữ liệu thành một biểu đồ, trong đó các cột được tạo ra về cơ bản là con trỏ và bạn chỉ duyệt qua từ cột này sang bước tiếp theo. Tôi nghĩ rằng ném đi tất cả sự vĩ đại của một hệ thống quan hệ. Nếu bạn lùi lại và suy nghĩ về nó, bạn sẽ giới thiệu một loạt các cột không có ý nghĩa gì đối với doanh nghiệp của bạn. Bạn có thể quan tâm đến số related blog post của tôi.

3

Khá nhiều lần duy nhất tôi sử dụng khóa chính kết hợp là khi phần thứ tự cao của khóa là chìa khóa cho bảng khác. Ví dụ, tôi có thể tạo một bảng OrderLineItem với một khóa chính của OrderId + LineNumber. Khi nhiều truy cập vào bảng OrderLineItem sẽ là "thứ tự tham gia orderlineitem bằng cách sử dụng (orderid)" hoặc một số biến thể của điều đó, điều này thường có ích. Nó cũng làm cho nó dễ dàng khi nhìn vào các bãi cơ sở dữ liệu để tìm ra những mục hàng nào được kết nối với thứ tự nào.

Như những người khác đã lưu ý, các phím tổng hợp là một cơn đau trong hầu hết các trường hợp khác bởi vì việc tham gia của bạn phải liên quan đến tất cả các phần. Đó là loại để có nghĩa là nhiều khả năng cho những sai lầm, truy vấn chậm hơn, vv.

Phím hai phần không phải là xấu; Tôi làm những điều đó khá thường xuyên. Tôi không muốn sử dụng khóa ba phần. Hơn ba phần, tôi muốn nói là quên nó đi.

Trong ví dụ của bạn, tôi nghi ngờ có ít thu được bằng cách sử dụng phím tổng hợp. Chỉ cần phát minh ra một số thứ tự mới và để mã nguồn và khóa nguồn là các thuộc tính thông thường.

2

Tôi gặp phải sự cố khi sử dụng nhiều khóa tổng hợp và vì vậy tôi không khuyên bạn nên sử dụng nó (dưới đây), tôi cũng tìm thấy lợi ích trong khóa độc lập/thay thế (thay vì tự nhiên) khi cố gắng cuộn lại lỗi người dùng. Vấn đề là thông qua một tập hợp các mối quan hệ, một bảng đã nối hai bảng cho mỗi phần của hỗn hợp giống nhau (điều này phù hợp ở dạng bình thường thứ 3 - so sánh giữa hai phần của một phần tử cha). Tôi đã hủy trùng lặp phần đó của mối quan hệ tổng hợp trong bảng kết nối (vì vậy thay vì parent1ID, other1ID, parent2ID, other2ID có parentID, other1ID, other2ID) nhưng bây giờ mối quan hệ không thể cập nhật thay đổi cho khóa chính, bởi vì nó đã thử để làm điều đó hai lần thông qua mỗi tuyến đường và không thành công ở giữa.

Các vấn đề liên quan