Tôi có nên đánh dấu một chỉ mục tổng hợp là duy nhất nếu nó chứa khóa chính không?


9

Đưa ra một số bảng có khóa chính, vd:

CREATE TABLE Customers (
   CustomerID int NOT NULL PRIMARY KEY,
   FirstName nvarchar(50),
   LastName nvarchar(50),
   Address nvarchar(200),
   Email nvarchar(260)
   --...
)

chúng tôi có một khóa chính duy nhất trên CustomerID.

Theo truyền thống, sau đó tôi có thể cần một số chỉ số bao gồm bổ sung; ví dụ để nhanh chóng tìm thấy người dùng bằng cách CustomerIDhoặc Email:

CREATE INDEX IX_Customers_CustomerIDEmail ON Customers
(
   CustomerID,
   Email
)

Và đây là những loại chỉ mục tôi đã tạo ra trong nhiều thập kỷ.

Nó không bắt buộc phải là duy nhất, nhưng thực ra nó là

Chỉ mục tồn tại để tránh quét bảng; nó là một chỉ số bao trùm để hỗ trợ hiệu suất (chỉ số không có ở đó như một ràng buộc để thực thi tính duy nhất).

Hôm nay tôi nhớ một mẩu thông tin - SQL Server có thể sử dụng thực tế rằng:

  • một cột có ràng buộc khóa ngoại
  • một cột có một chỉ mục duy nhất
  • một ràng buộc là đáng tin cậy

để giúp nó tối ưu hóa việc thực hiện truy vấn của mình. Trong thực tế, từ Hướng dẫn thiết kế chỉ mục SQL Server :

Nếu dữ liệu là duy nhất và bạn muốn thực thi tính duy nhất, việc tạo một chỉ mục duy nhất thay vì chỉ mục nonunique trên cùng một cột cung cấp thông tin bổ sung cho trình tối ưu hóa truy vấn có thể tạo ra các kế hoạch thực hiện hiệu quả hơn . Tạo một chỉ mục duy nhất (tốt nhất là bằng cách tạo một ràng buộc ĐỘC ĐÁO) được khuyến nghị trong trường hợp này.

Cho rằng chỉ mục nhiều cột của tôi chứa khóa chính, chỉ số tổng hợp này trên thực tế sẽ là duy nhất. Đây không phải là một ràng buộc mà tôi đặc biệt cần SQL Server để thực thi trong mỗi lần chèn hoặc cập nhật; nhưng thực tế là chỉ số không phân cụm này là duy nhất.

Có bất kỳ lợi thế nào trong việc đánh dấu chỉ số duy nhất trên thực tế này là thực sự duy nhất không?

TẠO ĐỘC LẬP ĐỘC LẬP IX_Customers_CustomerIDEmail TRÊN khách hàng
(
   ID khách hàng,
   E-mail
)

Dường như với tôi, SQL Server thể đủ thông minh để nhận ra rằng chỉ mục của tôi duy nhất nhờ thực tế là nó chứa khóa chính.

  • Nhưng có lẽ nó không biết điều này và có một lợi thế cho trình tối ưu hóa nếu tôi tuyên bố chỉ số là duy nhất.
  • Ngoại trừ có lẽ điều đó có thể dẫn đến sự chậm lại trong quá trình chèn và cập nhật, nơi nó phải thực hiện kiểm tra tính duy nhất - nơi mà trước đây nó chưa bao giờ phải thực hiện.
  • Trừ khi nó biết chỉ số được đảm bảo là duy nhất, bởi vì nó chứa khóa chính.

Tôi không thể tìm thấy bất kỳ hướng dẫn nào từ Microsoft về việc cần làm khi chỉ mục tổng hợp chứa khóa chính.

Lợi ích của các chỉ mục duy nhất bao gồm:

  • Tính toàn vẹn dữ liệu của các cột được xác định được đảm bảo.
  • Thông tin bổ sung hữu ích cho trình tối ưu hóa truy vấn được cung cấp.

Tôi có nên đánh dấu một chỉ mục tổng hợp là duy nhất nếu nó đã chứa khóa chính? Hoặc SQL Server có thể tự tìm ra điều này không?


4
Để nhanh chóng tìm thấy một khách hàng bằng CustomerID, PK có lẽ là đủ. Để tìm khách hàng bằng e-mail, tôi muốn có chỉ mục thứ hai chỉ trên e-mail (nó đã bao gồm khóa phân cụm). Dù sao, tôi biết điều này là hư cấu, nhưng vâng, tôi sẽ đánh dấu nó là duy nhất nếu bạn biết nó phải là duy nhất, ràng buộc đó có lẽ không thể làm tổn thương đủ để bù đắp cho các trường hợp có thể giúp tối ưu hóa. Nhưng, tất cả phụ thuộc vào khối lượng công việc của bạn, mà chúng ta sẽ phải suy đoán về ...
Aaron Bertrand

1
Chúng tôi đã thảo luận về nó ở đây. Và mặc dù chúng tôi không thể nghĩ ra bất kỳ cách nào để đưa ra bất kỳ dữ liệu nào để chứng minh bằng cách này hay cách khác, chúng tôi cho rằng các máy chủ SQL có thể rất thông minh và trình tối ưu hóa có thể đã thực hiện tối ưu hóa meta này. Chúng tôi cũng cho rằng có lẽ tốt nhất là để chỉ mục truyền đạt ý định - đơn giản chỉ là một chỉ mục và không áp đặt tính duy nhất như một quy tắc kinh doanh khi nó chỉ được thực hiện để cố gắng đoán các khả năng của SQL Server.
Ian Boyd

Câu trả lời:


11

Tôi có nên đánh dấu một chỉ mục tổng hợp là duy nhất nếu nó đã chứa khóa chính không?

Chắc là không. Trình tối ưu hóa nói chung có thể sử dụng thông tin về tính duy nhất của cột khóa được chứa, vì vậy không có lợi thế thực sự.

Ngoài ra còn có một hệ quả quan trọng của việc đánh dấu một chỉ mục duy nhất trên các gói cập nhật sửa đổi các khóa của chỉ mục đó để xem xét:

Thiết lập

CREATE TABLE dbo.Customers 
(
   CustomerID int NOT NULL PRIMARY KEY,
   FirstName nvarchar(50),
   LastName nvarchar(50),
   [Address] nvarchar(200),
   Email nvarchar(260)
);

CREATE NONCLUSTERED INDEX 
    IX_Customers_CustomerIDEmail 
ON dbo.Customers
(
   CustomerID,
   Email
);

-- Pretend we have some rows
UPDATE STATISTICS dbo.Customers 
WITH ROWCOUNT = 100000, PAGECOUNT = 20000;

Gói cập nhật theo chỉ số (chỉ mục không duy nhất)

UPDATE dbo.Customers 
SET Email = N'New', [Address] = 'New Address'
WHERE Email = N'Old' 
OPTION (QUERYTRACEON 8790); -- Per-index update plan

Kế hoạch thực hiện:

Tách & Lọc

Trình tối ưu hóa thường đưa ra quyết định dựa trên chi phí giữa việc cập nhật các chỉ mục không bao gồm mỗi hàng (kế hoạch 'hẹp') hoặc mỗi chỉ mục (kế hoạch 'rộng'). Chiến lược mặc định (ngoại trừ các bảng OLTP trong bộ nhớ) là một kế hoạch rộng.

Các kế hoạch hẹp (nơi các chỉ mục không bao gồm được duy trì cùng lúc với chỉ mục heap / clustered) là một tối ưu hóa hiệu suất cho các cập nhật nhỏ. Tối ưu hóa này không được thực hiện cho tất cả các trường hợp - sử dụng các tính năng nhất định (như chế độ xem được lập chỉ mục) có nghĩa là (các) chỉ mục được liên kết sẽ được duy trì trong một kế hoạch rộng.

Thông tin thêm: Tối ưu hóa các truy vấn T-SQL thay đổi dữ liệu

Trong trường hợp này, tôi đã sử dụng cờ theo dõi không có giấy tờ 8790 để buộc một kế hoạch cập nhật rộng rãi: Do đó, kế hoạch này cho thấy các chỉ mục được nhóm và không bao gồm được duy trì riêng biệt.

Split chia mỗi bản cập nhật thành một cặp xóa & chèn riêng; Bộ lọc lọc ra bất kỳ hàng nào sẽ không dẫn đến thay đổi chỉ mục.

Thông tin thêm: ( Bản cập nhật không cập nhật ) của Nhóm QO của SQL Server.

Gói cập nhật theo chỉ số (chỉ mục duy nhất)

-- Same index, but unique
CREATE UNIQUE INDEX IX_Customers_CustomerIDEmail ON Customers
(
   CustomerID,
   Email
)
WITH (DROP_EXISTING = ON);

UPDATE dbo.Customers 
SET Email = N'New', [Address] = 'New Address'
WHERE Email = N'Old' 
OPTION (QUERYTRACEON 8790); -- Per-index update plan

Kế hoạch thực hiện:

Chia-Sắp xếp-Thu gọn

Lưu ý các toán tử Sắp xếp và Thu gọn bổ sung khi chỉ mục được đánh dấu là duy nhất.

Mẫu Chia-Sắp xếp-Thu gọn này được yêu cầu khi cập nhật các khóa của một chỉ mục duy nhất, để ngăn chặn các vi phạm khóa duy nhất trung gian.

Thông tin thêm: Duy trì các chỉ mục duy nhất của Craig Freedman

Sắp xếp đặc biệt có thể là một vấn đề. Không chỉ là một chi phí phụ không cần thiết, nó có thể tràn vào đĩa nếu ước tính không chính xác.

Về các phím không bao gồm

Một yếu tố khác cần xem xét là các cấu trúc chỉ mục không bao gồm luôn là duy nhất, ở mọi cấp độ của chỉ mục, ngay cả khi UNIQUEkhông được chỉ định. (Các) khóa phân cụm - và có thể là một trình duy nhất nếu chỉ mục cụm không được đánh dấu là duy nhất - được thêm vào một chỉ mục không độc nhất ở tất cả các cấp.

Kết quả là, chỉ số sau đây xác định:

CREATE INDEX IX_Customers_CustomerIDEmail ON Customers
(
   Email
)
WITH (DROP_EXISTING = ON);

... Thực sự có chứa các khóa (Email, CustomerID) ở tất cả các cấp. Do đó, 'có thể tìm kiếm' trên cả hai cột:

SELECT * 
FROM dbo.Customers AS C WITH (INDEX(IX_Customers_CustomerIDEmail))
WHERE C.Email = N'Email'
AND C.CustomerID = 1;

Tìm kiếm

Thông tin thêm: Thông tin thêm về Khóa chỉ mục không bao gồm của Kalen Delaney


8

SQL biết nó là duy nhất (nếu bao gồm PK, nó không thể có thêm tính độc đáo nào nữa), bất kể bạn có nói rõ ràng hay không.

Sự khác biệt lớn giữa chỉ mục không duy nhất và chỉ mục duy nhất là chỉ mục không duy nhất yêu cầu khóa chỉ mục được nhóm (với giá trị duy nhất nếu CIX không được khai báo là duy nhất) ở các cấp cao hơn của chỉ mục, không chỉ ở lá cấp độ.

Trong trường hợp của bạn, bạn đã có CIX trong khóa, điều đó có nghĩa là nó sẽ ở mọi cấp độ của chỉ mục.

Nhưng bạn có thể tạo một bảng có PK riêng (duy nhất) và CIX (không quan trọng). Sau đó tạo một chỉ mục không duy nhất bao gồm PK trong khóa của nó. Đặt một số hàng vào bảng, bao gồm một số giá trị varchar dễ tìm thấy cho cột CIX của bạn. Đặt đủ hàng vào để gây ra nhiều cấp chỉ mục của bạn. Sau đó, bạn có thể sử dụng DBCC IND để tìm các trang trong NCIX và TRANG DBCC của bạn để mở một số để xem dữ liệu, để xem các giá trị khóa CIX có ở mức cao hơn không.

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.