Hiệu suất khác biệt giữa Chỉ số phân cụm và Không phân cụm


22

Tôi đã đọc ClusteredNon Clustered Indexes.

Clustered Index- Nó chứa các trang dữ liệu. Điều đó có nghĩa là thông tin hàng đầy đủ sẽ có mặt trong Cột chỉ mục cụm.

Non Clustered Index- Nó chỉ chứa thông tin Bộ định vị hàng dưới dạng cột Chỉ mục cụm (nếu có) hoặc Bộ thụt tệp + Số trang + Tổng số hàng trong một trang. Điều này có nghĩa là công cụ truy vấn phải thực hiện một bước bổ sung để xác định vị trí dữ liệu thực tế.

Truy vấn - Làm cách nào tôi có thể kiểm tra sự khác biệt về hiệu suất với sự trợ giúp của một ví dụ thực tế vì chúng tôi biết rằng bảng chỉ có thể có một Clustered Indexvà cung cấp sortingtại Clustered Index ColumnNon Clustered Indexkhông cung cấp sortingvà có thể hỗ trợ 999 Non Clustered Indexesin SQL Server 2008và 249 in SQL Server 2005.


2
Hiệu suất khác biệt khi bạn làm gì?, Loại công việc bạn muốn làm với bảng đó?, Không có một giải pháp duy nhất phù hợp với mọi nhu cầu
Lamak

2
Một số thảo luận hữu hình ở đây có lẽ. stackoverflow.com/questions/91688/... stackoverflow.com/questions/5070529/... stackoverflow.com/questions/1251636/... Chúng tôi có thể viết một luận án về sự khác biệt giữa chỉ số nhóm và phi clustered, nhưng tôi không nghĩ rằng chúng tôi sẽ nói bất cứ điều gì chưa có sẵn để bạn đọc.
Aaron Bertrand

4
Bạn đã viết: "Điều này có nghĩa là công cụ truy vấn phải thực hiện một bước bổ sung để xác định vị trí dữ liệu thực tế." Trên thực tế, nếu tất cả những gì bạn cần là các cột được bao phủ trong chỉ mục , bạn không cần thực hiện thêm bất kỳ bước nào sau khi bạn tìm thấy các hàng mục tiêu của mình trong chỉ mục không bao gồm. Chỉ khi bạn cần các cột không được bao phủ bởi chỉ mục không bao gồm thì SQL Server mới cần thực hiện tra cứu dấu trang .
Nick Chammas

Câu trả lời:


43

Câu hỏi rất hay vì nó là một khái niệm quan trọng như vậy. Đây là một chủ đề lớn và những gì tôi sẽ chỉ cho bạn là một sự đơn giản hóa để bạn có thể hiểu các khái niệm cơ bản.

Thứ nhất khi bạn nhìn thấy chỉ số clustered nghĩ bàn . Trong máy chủ SQL nếu một bảng không chứa chỉ mục được nhóm thì đó là một đống. Tạo một chỉ mục cụm trên bảng thực sự biến đổi bảng thành cấu trúc kiểu b-cây. Chỉ mục được nhóm của bạn LÀ bảng của bạn, nó không tách rời khỏi bảng

Đã bao giờ tự hỏi tại sao bạn chỉ có thể có một chỉ số cụm? Chà, nếu chúng ta có hai chỉ mục được nhóm, chúng ta sẽ cần hai bản sao của bảng. Nó chứa dữ liệu sau khi tất cả.

Tôi sẽ cố gắng giải thích điều này bằng cách sử dụng một ví dụ đơn giản.

LƯU Ý: Tôi đã tạo bảng trong ví dụ này và điền vào đó với hơn 3 triệu mục ngẫu nhiên. Sau đó chạy các truy vấn thực tế và dán các kế hoạch thực hiện ở đây.

Những gì bạn thực sự cần phải nắm bắt là ký hiệu O hoặc hiệu quả hoạt động . Giả sử bạn có bảng sau.

CREATE TABLE [dbo].[Customer](
[CustomerID] [int] IDENTITY(1,1) NOT NULL,
[CustomerName] [varchar](100) NOT NULL,
[CustomerSurname] [varchar](100) NOT NULL,
CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED 
(
[CustomerID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF
  , IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS  = ON
  , ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Vì vậy, ở đây chúng ta có bảng cơ bản với một khóa được phân cụm trên CustomerID (Khóa chính được phân cụm theo mặc định). Do đó, bảng được sắp xếp / sắp xếp dựa trên khóa chính ID khách hàng. Các cấp độ trung gian sẽ chứa các giá trị CustomerID. Các trang dữ liệu sẽ chứa toàn bộ hàng do đó là hàng của bảng.

Chúng tôi cũng sẽ tạo một chỉ mục không được nhóm trên trường Tên khách hàng. Các mã sau đây sẽ làm điều đó.

CREATE NONCLUSTERED INDEX [ix_Customer_CustomerName] ON [dbo].[Customer] 
 (
[CustomerName] ASC
 )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF
  , SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF
  , DROP_EXISTING = OFF, ONLINE = OFF
  , ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

Vì vậy, trong chỉ mục này, bạn sẽ tìm thấy trên các trang dữ liệu / nút mức lá một con trỏ tới các mức trung gian trong chỉ mục được nhóm. Chỉ mục được sắp xếp / sắp xếp xung quanh trường CustomerName. Do đó, mức trung gian chứa các giá trị CustomerName và cấp độ lá sẽ chứa con trỏ (các giá trị con trỏ này thực sự là các giá trị khóa chính hoặc cột CustomerID).

Đúng vậy nếu chúng ta thực hiện truy vấn sau:

SELECT * FROM Customer WHERE CustomerID = 1 

SQL có thể sẽ đọc chỉ mục được nhóm thông qua một hoạt động tìm kiếm. Một hoạt động tìm kiếm là một tìm kiếm nhị phân hiệu quả hơn nhiều so với quét là một tìm kiếm tuần tự. Vì vậy, trong ví dụ trên của chúng tôi, chỉ mục được đọc và bằng cách sử dụng SQL tìm kiếm nhị phân có thể loại bỏ dữ liệu không phù hợp với tiêu chí mà chúng tôi đang tìm kiếm. Xem ảnh chụp màn hình đính kèm cho kế hoạch truy vấn.

nhập mô tả hình ảnh ở đây

Vì vậy, số lượng hoạt động hoặc ký hiệu O cho hoạt động tìm kiếm như sau:

  1. Thực hiện tìm kiếm nhị phân trên chỉ mục cụm bằng cách so sánh giá trị được tìm kiếm với các giá trị ở cấp độ trung gian.
  2. Trả về các giá trị khớp (nhớ vì chỉ mục được nhóm có tất cả dữ liệu trong đó có thể trả về tất cả các cột từ chỉ mục vì đây là dữ liệu hàng)

Vì vậy, nó là hai hoạt động. Tuy nhiên nếu chúng tôi thực hiện truy vấn sau:

SELECT * FROM Customer WHERE CustomerName ='John'

Bây giờ SQL sẽ sử dụng chỉ mục không được nhóm trên Tên khách hàng để thực hiện tìm kiếm. Tuy nhiên vì đây là một chỉ mục không được nhóm nên nó không chứa tất cả dữ liệu trong hàng.

Vì vậy, SQL sẽ thực hiện tìm kiếm ở các cấp độ trung gian để tìm các bản ghi khớp với nhau sau đó thực hiện tra cứu bằng cách sử dụng các giá trị được trả về để thực hiện một tìm kiếm khác trên chỉ mục được nhóm (còn gọi là bảng) để lấy dữ liệu thực tế. Điều này nghe có vẻ khó hiểu tôi biết nhưng đọc tiếp và tất cả sẽ trở nên rõ ràng.

Vì chỉ mục không được nhóm của chúng tôi chỉ chứa trường Tên khách hàng (các giá trị trường được lập chỉ mục được lưu trữ trong các nút trung gian) và con trỏ tới dữ liệu là ID khách hàng, nên chỉ mục không có bản ghi của Khách hàng. Tên khách hàng phải được tìm nạp từ chỉ mục hoặc bảng được nhóm.

Khi chạy truy vấn này, tôi nhận được kế hoạch thực hiện sau:

nhập mô tả hình ảnh ở đây

Có hai điều quan trọng để bạn chú ý trong ảnh chụp màn hình ở trên

  1. SQL đang nói rằng tôi có một chỉ mục bị thiếu (văn bản màu xanh lá cây). SQL đang đề nghị tôi tạo một chỉ mục trên Tên khách hàng, bao gồm cả ID khách hàng và Khách hàng.
  2. Bạn cũng sẽ thấy rằng 99% thời gian của truy vấn được dành cho việc thực hiện tra cứu khóa trên chỉ mục khóa chính / chỉ mục cụm.

Tại sao SQL lại đề xuất chỉ mục trên Tên khách hàng? Chà vì chỉ mục chỉ chứa ID khách hàng và SQL của khách hàng vẫn phải tìm Tên khách hàng từ các chỉ mục bảng / cụm.

Nếu chúng tôi tạo chỉ mục và chúng tôi đã bao gồm cột Khách hàng Tên trong chỉ mục, SQL sẽ có thể đáp ứng toàn bộ truy vấn bằng cách chỉ đọc chỉ mục không được phân cụm. Đây là lý do tại sao SQL đề nghị tôi thay đổi chỉ mục không phân cụm của mình.

Ở đây bạn có thể thấy hoạt động bổ sung mà SQL cần thực hiện để lấy cột CustomerSurname từ khóa được nhóm

Do đó, số lượng các hoạt động như sau:

  1. Thực hiện tìm kiếm nhị phân trên chỉ mục không phân cụm bằng cách so sánh giá trị được tìm kiếm với các giá trị ở cấp độ trung gian
  2. Đối với các nút phù hợp, hãy đọc nút cấp độ lá sẽ chứa con trỏ cho dữ liệu trong chỉ mục được nhóm (các nút cấp độ lá sẽ chứa các giá trị khóa chính theo cách này).
  3. Đối với mỗi giá trị được trả về, hãy đọc chỉ mục được nhóm (bảng) để lấy các giá trị hàng ở đây, chúng tôi sẽ đọc Tên khách hàng.
  4. Trả về các hàng khớp

Đó là 4 thao tác để lấy các giá trị ra. Hai lần số lượng hoạt động cần thiết so với việc đọc chỉ mục cụm. Điều này cho bạn thấy rằng chỉ mục được nhóm của bạn là chỉ mục mạnh nhất của bạn vì nó chứa tất cả dữ liệu.

Vì vậy, chỉ để làm rõ một điểm cuối cùng. Tại sao tôi nói rằng con trỏ trong chỉ mục không được nhóm là giá trị khóa chính? Vâng để chứng minh rằng các nút cấp độ lá của chỉ mục không được nhóm chứa giá trị khóa chính tôi thay đổi truy vấn của mình thành:

SELECT CustomerID
FROM Customer
WHERE CustomerName='Jane'

Trong truy vấn này, SQL có thể đọc CustomerID từ chỉ mục không được nhóm. Nó không cần phải tìm kiếm trên chỉ mục cụm. Điều này bạn có thể thấy bởi kế hoạch thực hiện trông như thế này.

nhập mô tả hình ảnh ở đây

Lưu ý sự khác biệt giữa truy vấn này và truy vấn trước. Không có tra cứu. SQL có thể tìm thấy tất cả dữ liệu trong chỉ mục không được phân cụm

Hy vọng rằng bạn có thể bắt đầu hiểu rằng chỉ mục được phân cụm là bảng và các chỉ mục không được phân cụm KHÔNG chứa tất cả dữ liệu. Lập chỉ mục sẽ tăng tốc các lựa chọn do thực tế là các tìm kiếm nhị phân có thể được thực hiện nhưng chỉ các chỉ mục được nhóm chứa tất cả dữ liệu. Vì vậy, tìm kiếm trên một chỉ mục không được phân cụm sẽ hầu như luôn luôn dẫn đến các giá trị được tải từ chỉ mục được phân cụm. Các hoạt động bổ sung này làm cho các chỉ mục không được phân cụm kém hiệu quả hơn một chỉ mục được phân cụm.

Hy vọng điều này sẽ làm rõ ràng mọi thứ. Nếu bất cứ điều gì không có ý nghĩa xin vui lòng gửi bình luận và tôi sẽ cố gắng làm rõ. Ở đây khá muộn và não tôi cảm thấy một chút phẳng lặng. Thời gian cho một con bò đỏ.


Tôi có một câu hỏi. WHy là tìm kiếm một chỉ mục tìm kiếm trên chỉ mục không được nhóm trên Tên khách hàng cho truy vấn này CHỌN * TỪ Khách hàng WHERE CustomerName = 'John'. Vì nó là một chỉ mục không được nhóm, tên người dùng sẽ không được sắp xếp. Vì vậy, không nên quét chỉ mục.
ckv

BTW Câu trả lời tuyệt vời hoàn toàn hiểu được ngoại trừ câu hỏi trên.
ckv

1
Một chỉ mục được sắp xếp theo thứ tự của dữ liệu. Ví dụ, nó sẽ được sắp xếp theo tên của Khách hàng vì đó là giá trị được lập chỉ mục. Vì vậy, nó được sắp xếp. Hãy nhớ rằng nó vẫn phải quét cấp độ lá hoặc trang.
Namphibian

9

"Điều này có nghĩa là công cụ truy vấn phải thực hiện một bước bổ sung để xác định vị trí dữ liệu thực tế."

Không nhất thiết - nếu chỉ mục bao trùm cho một truy vấn nhất định, không có chuyến đi nào được thực hiện cho các trang dữ liệu. Ngoài ra, với các cột được bao gồm, các cột bổ sung có thể được thêm vào một chỉ mục không được nhóm để làm cho nó bao phủ mà không làm thay đổi kích thước khóa.

Vì vậy, câu trả lời cuối cùng là - Nó phụ thuộc (vào nhiều thông tin hơn bạn có thể thực sự bao gồm trong một câu hỏi) - bạn cần hiểu tất cả các khả năng của các chỉ mục và kế hoạch thực hiện cho một truy vấn nhất định có thể khác với mong đợi của bạn.

Một nguyên tắc chung mà tôi có là một bảng luôn có một chỉ mục được nhóm (và thường là trên một danh tính hoặc GUID tuần tự), nhưng các chỉ mục không được phân cụm được thêm vào để thực hiện. Nhưng luôn có những trường hợp ngoại lệ - bảng heap có một vị trí, các chỉ mục cụm rộng hơn có một vị trí. Dường như các chỉ mục dư thừa hẹp hơn để phù hợp với nhiều hàng hơn trên mỗi trang có một vị trí. Vân vân.

Và tôi sẽ không lo lắng về các giới hạn đối với các chỉ số khác nhau được phép - điều đó gần như chắc chắn sẽ không xuất hiện trong nhiều ví dụ thực tế.


2
+1 cho there are always exceptions- quá nhiều người bỏ qua điều này và nghĩ rằng mọi chỉ số được nhóm nên int identitykhông có vấn đề gì.
JNK
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.