Khóa chính hoặc chỉ mục duy nhất?


127

Trong công việc, chúng tôi có một cơ sở dữ liệu lớn với các chỉ mục duy nhất thay vì các khóa chính và tất cả đều hoạt động tốt.

Tôi đang thiết kế cơ sở dữ liệu mới cho một dự án mới và tôi có một vấn đề nan giải:

Trong lý thuyết DB, khóa chính là yếu tố cơ bản, điều đó không sao, nhưng trong các dự án THỰC SỰ, ưu điểm và nhược điểm của cả hai là gì?

Bạn sử dụng gì trong các dự án?

EDIT: ... còn các khóa chính và sao chép trên máy chủ MS SQL thì sao?


2
Có một số cân nhắc bổ sung được thảo luận ở đây (mặc dù với bối cảnh bổ sung của một chỉ số bao trùm) - dba.stackexchange.com/questions/21554/ trộm
StuartLC

LƯU Ý: SQLite khác ở chỗ chúng cho phép khóa chính là null, trái với tiêu chuẩn chung do vấn đề di sản. sqlite.org/lang_createtable.html
bitinn

Câu trả lời:


168

Một chỉ số duy nhất là gì?

Một chỉ mục duy nhất trên một cột là một chỉ mục trên cột đó cũng thực thi ràng buộc rằng bạn không thể có hai giá trị bằng nhau trong cột đó ở hai hàng khác nhau. Thí dụ:

TẠO BẢNG bảng1 (foo int, bar int);
TẠO INDEX UNIITE ux_table1_foo TRÊN bảng1 (foo); - Tạo chỉ mục duy nhất trên foo.

XÁC NHẬN VÀO bảng1 (foo, bar) GIÁ TRỊ (1, 2); -- ĐỒNG Ý
XÁC NHẬN VÀO bảng1 (foo, bar) GIÁ TRỊ (2, 2); -- ĐỒNG Ý
XÁC NHẬN VÀO bảng1 (foo, bar) GIÁ TRỊ (3, 1); -- ĐỒNG Ý
XÁC NHẬN VÀO bảng1 (foo, bar) GIÁ TRỊ (1, 4); - Thất bại!

Mục trùng lặp '1' cho khóa 'ux_table1_foo'

Chèn cuối cùng không thành công vì nó vi phạm chỉ mục duy nhất trên cột foo khi nó cố gắng chèn giá trị 1 vào cột này lần thứ hai.

Trong MySQL, một ràng buộc duy nhất cho phép nhiều NULL.

Có thể tạo một chỉ mục duy nhất trên các cột đa dạng.

Khóa chính so với chỉ mục duy nhất

Những thứ giống nhau:

  • Khóa chính ngụ ý một chỉ mục duy nhất.

Những điều khác biệt:

  • Khóa chính cũng ngụ ý KHÔNG NULL, nhưng một chỉ mục duy nhất có thể là null.
  • Có thể chỉ có một khóa chính, nhưng có thể có nhiều chỉ mục duy nhất.
  • Nếu không có chỉ mục cụm được xác định thì khóa chính sẽ là chỉ mục được nhóm.

4
Lưu ý rằng một chỉ mục duy nhất là một chỉ mục trên một cột không hoàn toàn chính xác vì một chỉ mục duy nhất hoặc khóa chính có thể bao gồm nhiều hơn một cột.
Alex Jasmin

2
@Alexandre Jasmin: Đã sửa cảm ơn. Phần về nhiều cột được đề cập sau.
Mark Byers

Với tham chiếu đến null, các tiêu chuẩn ansi cho phép nhiều giá trị null trong một tập dữ liệu với một ràng buộc duy nhất trên đó và đó cũng là cách triển khai trên Oracle và PostgreQuery. Tôi tin rằng SQL Server chỉ cho phép một giá trị null.
David Aldridge

3
nhưng tôi vẫn không nhận được nó, như khi nào nên sử dụng khóa chính hay khi nào nên sử dụng chỉ mục duy nhất? hoặc có thể là cả hai trong cùng một tình huống.
Amit

33

Bạn có thể thấy nó như thế này:

Khóa chính là duy nhất

Giá trị duy nhất không nhất thiết phải là Đại diện của nguyên tố

Ý nghĩa?; Vâng, khóa chính được sử dụng để xác định thành phần, nếu bạn có "Người", bạn muốn có Số nhận dạng cá nhân (SSN hoặc tương tự) là Chính cho Người của bạn.

Mặt khác, người đó có thể có một email duy nhất, nhưng không xác định được người đó.

Tôi luôn có Khóa chính, ngay cả trong các bảng quan hệ (bảng giữa / bảng kết nối) tôi có thể có chúng. Tại sao? Vâng, tôi thích tuân theo một tiêu chuẩn khi mã hóa, nếu "Người" có mã định danh, Xe cũng có mã định danh, thì Người -> Xe cũng nên có mã định danh!


Trong các bảng mối quan hệ của bạn: bạn có nghĩa là bạn giới thiệu một cột mới với khóa chính nhân tạo (ví dụ một số nguyên) hoặc bạn có sử dụng khóa chính tổng hợp (person_id, car_id) không?

3
khóa chính (person_id, car_id) sẽ là tốt nhất. Nhưng tôi thường tạo một cột mới, chắc chắn rằng nó mang lại một số chi phí nhưng tôi đã xem nó là tốt. Bạn không bao giờ biết nếu bạn muốn liên quan đến một mối quan hệ cụ thể trong một kịch bản sau này.
Filip Ekberg

1
Một điều khác mà khóa chính thay thế làm cho bảng tổng hợp / tham gia của bạn là dễ dàng bảo trì các tác vụ thủ công.
Robert C. Barth

2
Bạn chỉ cần một chìa khóa chính nếu bạn sắp có con. Tại sao thêm một cột và một chuỗi nếu giá trị không xuất hiện, nếu giá trị được sử dụng cho không có gì? Đó là công việc để ngăn Access truy cập PK. Tạo PK nếu bạn cần xác định hồ sơ ở trẻ, nếu không thì thật lãng phí.

3
Nếu nó không liên quan gì đến quan hệ thì nó phải làm gì? Bạn chỉ vào một lĩnh vực và nói, đó là chính. Và? Sau đó điều gì xảy ra? Và nếu không có pk tự nhiên, tôi thêm một cột và một chuỗi và một trình kích hoạt và tất cả vì ____? Một số chỉ cần là chính. Tôi tránh những quy tắc mà không có lý do.

10

Khóa ngoại hoạt động với các ràng buộc duy nhất cũng như các khóa chính. Từ sách trực tuyến:

Một ràng buộc KEY NGOẠI TỆ không nhất thiết phải được liên kết với một ràng buộc KEY PRIMARY KEY trong một bảng khác; nó cũng có thể được định nghĩa để tham chiếu các cột của một ràng buộc ĐỘC ĐÁO trong một bảng khác

Để nhân rộng giao dịch, bạn cần khóa chính. Từ sách trực tuyến:

Các bảng được công bố để nhân rộng giao dịch phải có khóa chính. Nếu một bảng trong một ấn phẩm sao chép giao dịch, bạn không thể vô hiệu hóa bất kỳ chỉ mục nào được liên kết với các cột khóa chính. Các chỉ số này được yêu cầu bởi nhân rộng. Để vô hiệu hóa một chỉ mục, trước tiên bạn phải thả bảng từ ấn phẩm.

Cả hai câu trả lời đều dành cho SQL Server 2005.


Điều đó làm tôi kinh hoàng (trích dẫn đầu tiên). Tại sao? Tôi có một bảng người có ID tùy ý là PK của tôi nhưng tôi quyết định thêm Vương quốc Anh vào Điện thoại, Email và SSN ... vì vậy bây giờ 4 bảng khác nhau kết hợp với nhau trên 4 cột khác nhau? Tôi nghĩ rằng tôi đã từ bỏ bất kỳ sự linh hoạt nào bạn có thể có được cho sự nhất quán.

5

Việc lựa chọn thời điểm sử dụng khóa chính thay thế so với khóa tự nhiên là khó khăn. Các câu trả lời như, luôn luôn hoặc không bao giờ, hiếm khi hữu ích. Tôi thấy rằng nó phụ thuộc vào tình hình.

Ví dụ, tôi có các bảng sau:

CREATE TABLE toll_booths (
    id            INTEGER       NOT NULL PRIMARY KEY,
    name          VARCHAR(255)  NOT NULL,
    ...
    UNIQUE(name)
)

CREATE TABLE cars (
    vin           VARCHAR(17)   NOT NULL PRIMARY KEY,
    license_plate VARCHAR(10)   NOT NULL,
    ...
    UNIQUE(license_plate)
)

CREATE TABLE drive_through (
    id            INTEGER       NOT NULL PRIMARY KEY,
    toll_booth_id INTEGER       NOT NULL REFERENCES toll_booths(id),
    vin           VARCHAR(17)   NOT NULL REFERENCES cars(vin),
    at            TIMESTAMP     DEFAULT CURRENT_TIMESTAMP NOT NULL,
    amount        NUMERIC(10,4) NOT NULL,
    ...
    UNIQUE(toll_booth_id, vin)
)

Chúng tôi có hai bảng thực thể ( toll_boothscars) và bảng giao dịch ( drive_through). Các toll_boothbảng sử dụng một phím thay thế bởi vì nó không có thuộc tính tự nhiên mà không được bảo đảm để thay đổi (tên một cách dễ dàng có thể được thay đổi). Các carsbảng sử dụng một khóa chính tự nhiên bởi vì nó có một định danh không thay đổi duy nhất ( vin). Cácdrive_through giao dịch sử dụng khóa thay thế để dễ nhận biết, nhưng cũng có một ràng buộc duy nhất đối với các thuộc tính được đảm bảo là duy nhất tại thời điểm bản ghi được chèn.

http://database-programmer.blogspot.com có một số bài viết tuyệt vời về chủ đề cụ thể này.


4

Không có nhược điểm của khóa chính.

Để chỉ thêm một số thông tin vào câu trả lời @MrWiggles và @Peter Parker, khi bảng không có khóa chính, ví dụ bạn sẽ không thể chỉnh sửa dữ liệu trong một số ứng dụng (cuối cùng họ sẽ nói rằng không thể chỉnh sửa / xóa dữ liệu mà không có khóa chính). Postgresql cho phép nhiều giá trị NULL nằm trong cột UNIQUE, PRIMARY KEY không cho phép NULL. Ngoài ra, một số ORM tạo mã có thể có một số vấn đề với các bảng không có khóa chính.

CẬP NHẬT:

Theo tôi biết, không thể sao chép các bảng mà không có khóa chính trong MSSQL, ít nhất là không có vấn đề ( chi tiết ).


Có phí khi các hàng mới được chèn hoặc cột đó được cập nhật.

3

Nếu một cái gì đó là khóa chính, tùy thuộc vào công cụ DB của bạn, toàn bộ bảng sẽ được sắp xếp theo khóa chính. Điều này có nghĩa là việc tra cứu nhanh hơn nhiều trên khóa chính bởi vì nó không phải thực hiện bất kỳ hội thảo nào như nó phải làm với bất kỳ loại chỉ mục nào khác. Bên cạnh đó, đó chỉ là lý thuyết.


3
bảng sẽ được sắp xếp theo chỉ mục được nhóm không theo khóa chính.
Ray Booysen

1
điều đó chỉ xảy ra khi hầu hết mọi người đặt khóa chính của họ là chỉ mục được nhóm.
Ray Booysen

Điều mà chúng ta biết thường là một ý tưởng thực sự tồi tệ, trừ khi chúng ta thích các điểm nóng và cây chỉ số không cân bằng trong các bảng của chúng tôi, tất nhiên ...
Mike Woodhouse

1
Đó không phải là một ý tưởng thực sự tồi tệ. Biết dữ liệu của bạn, biết RDBMS của bạn, biết các lựa chọn có ý nghĩa gì. Hiếm khi lựa chọn LUÔN LUÔN tốt hay xấu. Nếu LUÔN là một, cơ sở dữ liệu sẽ ủy quyền hoặc không cho phép. Họ cho bạn lựa chọn vì 'Nó phụ thuộc.'

2

Ngoài những gì các câu trả lời khác đã nói, một số cơ sở dữ liệu và hệ thống có thể yêu cầu phải có mặt chính. Một tình huống đến với tâm trí; khi sử dụng nhân rộng doanh nghiệp với Informix, phải có PK để bảng tham gia sao chép.


2

Miễn là bạn không cho phép NULL cho một giá trị, chúng sẽ được xử lý như nhau, nhưng giá trị NULL được xử lý khác nhau trên cơ sở dữ liệu (AFAIK MS-SQL không cho phép nhiều hơn một (1) giá trị NULL, myQuery và Oracle cho phép điều này , nếu một cột là ĐỘC ĐÁO) Vì vậy, bạn phải xác định cột này KHÔNG PHẢI CHỈ ĐỘC ĐÁO


1
MS-SQL cho phép nhiều giá trị NULL trong một cột có một chỉ mục duy nhất, như mọi RDBMS. Hãy nghĩ về nó theo cách này: NULL không phải là một giá trị, vì vậy khi bạn chèn NULL thứ hai, nó sẽ không bao giờ khớp với giá trị hiện có. Biểu thức (NULL == NULL) không đánh giá đúng hay sai, nó đánh giá thành NULL.
gregmac

thanx gregmac, tôi không chắc chắn, nếu MS làm theo điều này. Tôi đã nhớ một số MS Quirks với điều này, tuy nhiên vài năm trước (trước năm 2000) và cũng có thể là một ho
Peter Parker

2

Không có thứ gọi là khóa chính trong lý thuyết dữ liệu quan hệ, vì vậy câu hỏi của bạn phải được trả lời ở cấp độ thực tế.

Các chỉ mục duy nhất không phải là một phần của tiêu chuẩn SQL. Việc triển khai cụ thể của DBMS sẽ xác định hậu quả của việc khai báo một chỉ mục duy nhất là gì.

Trong Oracle, việc khai báo khóa chính sẽ dẫn đến một chỉ mục duy nhất được tạo thay cho bạn, vì vậy câu hỏi gần như không có gì phải bàn cãi. Tôi không thể nói với bạn về các sản phẩm DBMS khác.

Tôi ủng hộ việc khai báo một khóa chính. Điều này có tác dụng cấm các NULL trong (các) cột chính cũng như cấm các bản sao. Tôi cũng ủng hộ việc khai báo các ràng buộc TÀI LIỆU THAM KHẢO để thực thi tính toàn vẹn của thực thể. Trong nhiều trường hợp, việc khai báo một chỉ mục trên coulmn (s) của khóa ngoại sẽ tăng tốc độ tham gia. Loại chỉ số này nói chung không phải là duy nhất.


Khóa chính trong MS SQL Server luôn luôn là UNIITE và KHÔNG NULL - ví dụ: đây thực sự chỉ là một chỉ mục duy nhất, nhưng với hạn chế được thêm vào đó không thể là NULL.
marc_s

Oracle có thể thực thi một ràng buộc duy nhất với một chỉ mục không duy nhất. Tôi sẽ ngạc nhiên nếu MSSS không thể. Nói rằng "nó thực sự chỉ là một chỉ mục duy nhất" là một sự bất đồng.

"Trong nhiều trường hợp, việc khai báo một chỉ mục trên coulmn (s) của khóa ngoại sẽ tăng tốc độ tham gia." điều này hầu như không luôn đúng trong một thế giới lưu trữ dữ liệu nơi các phép nối băm sẽ được ưu tiên hơn nếu có sẵn.
JAC2703

OP không đề cập đến kho. Tôi không chắc chắn làm thế nào các hàm băm hoạt động trên máy chủ sql. Bao nhiêu công việc có thể được thực hiện tại thời gian cập nhật kho.
Walter Mitty

2

Có một số nhược điểm của INDEX CLUSTERED so với INDEX UNIITE.

Như đã nêu, INDEX CLUSTERED sắp xếp vật lý dữ liệu trong bảng.

Điều này có nghĩa là khi bạn có rất nhiều nếu chèn hoặc xóa trên bảng chứa chỉ mục được nhóm, mọi lúc (tốt, hầu như, tùy thuộc vào hệ số điền của bạn), bạn thay đổi dữ liệu, bảng vật lý cần được cập nhật để được sắp xếp.

Trong các bảng tương đối nhỏ, điều này là tốt, nhưng khi đến các bảng có giá trị dữ liệu của GB và các tệp chèn / xóa ảnh hưởng đến việc sắp xếp, bạn sẽ gặp vấn đề.


Vậy thì lợi thế là gì? truy vấn được sắp xếp nhanh hơn? điều này có tốt hơn cho trường hợp sử dụng khi bạn viết hầu hết dữ liệu của mình một lần (hoặc hiếm khi) và truy vấn nó mọi lúc không?
Trâu

1

Tôi gần như không bao giờ tạo bảng mà không có khóa chính số. Nếu đó cũng là một khóa tự nhiên phải là duy nhất, tôi cũng đặt một chỉ mục duy nhất cho nó. Các phép nối nhanh hơn trên các số nguyên so với các khóa tự nhiên nhiều màu, dữ liệu chỉ cần thay đổi ở một nơi (các khóa tự nhiên có xu hướng cần được cập nhật, đó là một điều tồi tệ khi nó nằm trong khóa chính - mối quan hệ khóa ngoài). Nếu bạn cần sao chép, hãy sử dụng GUID thay vì số nguyên, nhưng đối với hầu hết các phần tôi thích một khóa mà người dùng có thể đọc được, đặc biệt nếu họ cần xem nó để phân biệt giữa John Smith và John Smith.

Một vài lần tôi không tạo khóa thay thế là khi tôi có một bảng tham gia có liên quan đến nhiều mối quan hệ. Trong trường hợp này tôi khai báo cả hai trường là khóa chính.


Tôi hầu như không bao giờ tạo bảng mà không có khóa chính số: Tại sao luôn luôn là số? Khóa chính không cần phải là số (bằng cách này cũng không cần phải là AUTO_INCREMENT).
Hibou57

@ Hinou57, vì tôi đã thấy rằng các phím tự nhiên hiếm khi thực sự là duy nhất và chúng hầu như luôn luôn có thể thay đổi. Tham gia thêm vào các intergers thường nhanh hơn nhiều so với tham gia vào các khóa tự nhiên varcahrr hoặc các khóa tổng hợp tệ hơn. Tôi sẽ không sử dụng chúng tối đa thời gian. Điều này có thể khác với loại thông tin bạn lưu trữ trong cơ sở dữ liệu của bạn, nhưng theo kinh nghiệm cá nhân của tôi, tôi đã tìm thấy các khóa tự nhiên cực kỳ không đáng tin cậy theo thời gian.
HLGEM

Cảm ơn đã trả lời HLGEM. Bạn có ý nghĩa gì với không đáng tin cậy? Hiệu suất? (Tôi hy vọng đó không phải là vấn đề về độ tin cậy theo nghĩa toàn vẹn dữ liệu). Tôi hơi ngạc nhiên về lời nói của bạn, vì tôi mặc dù sử dụng các khóa số nguyên hoặc các khóa tự nhiên hơn như VARCHAR ngắn, có thể sẽ tạo ra một sự khác biệt nhỏ vì băm được sử dụng ở mọi nơi ngay cả với các công cụ DB đơn giản nhất.
Hibou57

Họ không đáng tin cậy trong nhiều trường hợp vì họ không phải là duy nhất đáng tin cậy mặc dù họ được cho là. Chúng không đáng tin cậy vì chúng thay đổi và điều đó có thể ảnh hưởng đến hàng triệu hồ sơ trong một uopdate. Đây là kinh nghiệm của tôi khi thấy và quản lý hoặc truy vấn dữ liệu từ hoặc nhập dữ liệu từ hàng trăm cơ sở dữ liệu lưu trữ dữ liệu về nhiều loại thông tin khác nhau.
HLGEM

1

Tôi hiểu rằng một khóa chính và một chỉ mục duy nhất có ràng buộc không ‑ null, là như nhau (*); và tôi cho rằng người ta chọn cái này hay cái kia tùy thuộc vào những gì đặc tả nói rõ hoặc ngụ ý (một vấn đề về những gì bạn muốn thể hiện và thực thi rõ ràng). Nếu nó yêu cầu tính duy nhất và không ‑ null, thì hãy biến nó thành khóa chính. Nếu nó chỉ xảy ra tất cả các phần của một chỉ mục duy nhất không phải là null mà không có bất kỳ yêu cầu nào cho điều đó, thì hãy biến nó thành một chỉ mục duy nhất.

Sự khác biệt duy nhất còn lại là, bạn có thể có nhiều chỉ mục duy nhất không null, trong khi bạn không thể có nhiều khóa chính.

(*) Ngoại trừ sự khác biệt thực tế: khóa chính có thể là khóa duy nhất mặc định cho một số thao tác, như xác định khóa ngoại. Ví dụ. nếu người ta xác định khóa ngoại tham chiếu bảng và không cung cấp tên cột, nếu bảng được tham chiếu có khóa chính, thì khóa chính sẽ là cột được tham chiếu. Mặt khác, cột được tham chiếu sẽ phải được đặt tên rõ ràng.

Những người khác ở đây đã đề cập đến sao chép DB, nhưng tôi không biết về nó.


0

Chỉ số duy nhất có thể có một giá trị NULL. Nó tạo ra INDEX KHÔNG CLUSTERED. Khóa chính không thể chứa giá trị NULL. Nó tạo ra INDEX CLUSTERED.


0

Trong MSSQL, các khóa chính phải được tăng đơn điệu để có hiệu suất tốt nhất trên chỉ mục được nhóm. Do đó, một số nguyên có chèn danh tính sẽ tốt hơn bất kỳ khóa tự nhiên nào có thể không tăng đơn điệu.


-1

Nếu nó tùy thuộc vào tôi ...

Bạn cần đáp ứng các yêu cầu của cơ sở dữ liệu và các ứng dụng của bạn.

Việc thêm một số nguyên tự động hoặc cột id dài vào mỗi bảng để đóng vai trò là khóa chính đảm nhiệm các yêu cầu cơ sở dữ liệu.

Sau đó, bạn sẽ thêm ít nhất một chỉ mục duy nhất khác vào bảng để ứng dụng của bạn sử dụng. Đây sẽ là chỉ mục trên worker_id, hoặc account_id hoặc customer_id, v.v. Nếu có thể, chỉ mục này không phải là một chỉ mục tổng hợp.

Tôi sẽ ưu tiên các chỉ số trên một số lĩnh vực riêng lẻ trên các chỉ số tổng hợp. Cơ sở dữ liệu sẽ sử dụng các chỉ mục trường đơn bất cứ khi nào mệnh đề where bao gồm các trường đó, nhưng nó sẽ chỉ sử dụng hỗn hợp khi bạn cung cấp các trường theo đúng thứ tự - nghĩa là nó không thể sử dụng trường thứ hai trong chỉ mục tổng hợp trừ khi bạn cung cấp cả thứ nhất và thứ hai trong mệnh đề where của bạn.

Tôi là tất cả để sử dụng các chỉ số loại tính toán hoặc Hàm - và sẽ khuyên bạn nên sử dụng chúng trên các chỉ mục tổng hợp. Nó làm cho nó rất dễ sử dụng chỉ mục hàm bằng cách sử dụng cùng hàm trong mệnh đề where của bạn.

Điều này quan tâm đến các yêu cầu ứng dụng của bạn.

Rất có khả năng các chỉ số không chính khác thực sự là ánh xạ của giá trị khóa chỉ mục đó thành giá trị khóa chính, không phải là rowid (). Điều này cho phép các hoạt động sắp xếp vật lý và xóa xảy ra mà không phải tạo lại các chỉ số này.

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.