Tại sao trình tối ưu hóa lại chọn Chỉ mục cụm + Sắp xếp thay vì Chỉ mục không phân cụm?


11

Cho ví dụ tiếp theo:

IF OBJECT_ID('dbo.my_table') IS NOT NULL
    DROP TABLE [dbo].[my_table];
GO

CREATE TABLE [dbo].[my_table]
(
    [id]    int IDENTITY (1,1)  NOT NULL PRIMARY KEY,
    [foo]   int                 NULL,
    [bar]   int                 NULL,
    [nki]   int                 NOT NULL
);
GO

/* Insert some random data */
INSERT INTO [dbo].[my_table] (foo, bar, nki)
SELECT TOP (100000)
    ABS(CHECKSUM(NewId())) % 14,
    ABS(CHECKSUM(NewId())) % 20,
    n = CONVERT(INT, ROW_NUMBER() OVER (ORDER BY s1.[object_id]))
FROM 
    sys.all_objects AS s1 
CROSS JOIN 
    sys.all_objects AS s2
GO

CREATE UNIQUE NONCLUSTERED INDEX [IX_my_table]
    ON [dbo].[my_table] ([nki] ASC);
GO

Nếu tôi tìm nạp tất cả các bản ghi theo thứ tự [nki](Chỉ mục không phân cụm):

SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table ORDER BY nki;
SET STATISTICS TIME OFF;

SQL Server Execution Times: CPU time = 266 ms, elapsed time = 493 ms

Trình tối ưu hóa chọn chỉ mục được nhóm và sau đó áp dụng thuật toán Sắp xếp.

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

Execution plan

Nhưng nếu tôi buộc nó sử dụng chỉ mục không phân cụm:

SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table WITH(INDEX(IX_my_TABLE));
SET STATISTICS TIME OFF;

SQL Server Execution Times: CPU time = 311 ms, elapsed time = 188 ms

Sau đó, nó sử dụng chỉ mục không được nhóm với Tra cứu khóa:

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

Execution plan

Rõ ràng nếu chỉ mục không phân cụm được chuyển thành chỉ số bao phủ:

CREATE UNIQUE NONCLUSTERED INDEX [IX_my_table]
    ON [dbo].[my_table] ([nki] ASC)
    INCLUDE (id, foo, bar);
GO

Sau đó, nó chỉ sử dụng chỉ số này:

SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table ORDER BY nki;
SET STATISTICS TIME OFF;

SQL Server Execution Times: CPU time = 32 ms, elapsed time = 106 ms

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

Execution plan


Câu hỏi

  • Tại sao SQL Server sử dụng chỉ mục được phân cụm cộng với thuật toán sắp xếp thay vì sử dụng chỉ mục không được phân cụm ngay cả khi thời gian thực hiện nhanh hơn 38% trong trường hợp sau?

1
Ý của bạn là bỏ lệnh OR BY BY trong truy vấn chỉ mục bắt buộc của bạn?
Forrest

Câu trả lời:


9

Tại sao SQL Server sử dụng chỉ mục được phân cụm cộng với thuật toán sắp xếp thay vì sử dụng chỉ mục không được phân cụm ngay cả khi thời gian thực hiện nhanh hơn 38% trong trường hợp sau?

Bởi vì SQL Server sử dụng trình tối ưu hóa dựa trên chi phí dựa trên số liệu thống kê, không phải thông tin thời gian chạy.

Trong quá trình ước tính chi phí cho truy vấn này, nó thực sự đánh giá kế hoạch tra cứu, nhưng ước tính sẽ mất nhiều công sức hơn. (Lưu ý "Chi phí phụ ước tính" khi di chuột qua CHỌN trong kế hoạch thực hiện). Đó cũng không hẳn là một giả định tồi - trên máy thử nghiệm của tôi, kế hoạch tra cứu chiếm 6 lần CPU của sắp xếp / quét.

Hãy xem câu trả lời của Rob Farley về lý do tại sao SQL Server có thể chi phí cho kế hoạch tra cứu cao hơn.


9

Nếu bạn so sánh số lần đọc cần thiết trong 100.000 lần tra cứu với những gì liên quan đến việc sắp xếp, bạn có thể nhanh chóng biết được lý do tại sao Trình tối ưu hóa truy vấn cho rằng CIX + Sắp xếp sẽ là lựa chọn tốt nhất.

Việc thực hiện Tra cứu kết thúc nhanh hơn vì các trang đang đọc nằm trong bộ nhớ (ngay cả khi bạn xóa bộ đệm, bạn có rất nhiều hàng trên mỗi trang, do đó, bạn đọc cùng một trang nhiều lần, nhưng với số lượng phân mảnh khác nhau hoặc áp lực bộ nhớ khác với hoạt động khác, điều này có thể không xảy ra). Thực sự sẽ không mất nhiều thời gian để CIX + Sắp xếp nhanh hơn, nhưng những gì bạn đang thấy là vì chi phí của một lần đọc không tính đến sự rẻ tiền tương đối của việc lặp đi lặp lại cùng một trang.


4

Tôi đã quyết định đào sâu một chút về câu hỏi này và tôi đã tìm ra một số tài liệu thú vị nói về cách thức và thời điểm sử dụng hoặc có thể tốt hơn, không (buộc) sử dụng một chỉ mục không phân cụm.

Theo đề xuất theo nhận xét của John Eisbrener , một trong những blog được tham khảo nhiều nhất, ngay cả trong các blog khác, là bài viết thú vị này của Kimberly L. Tripp:

nhưng nó không phải là duy nhất, nếu bạn quan tâm, bạn có thể xem các trang này:

Như bạn có thể thấy, tất cả chúng đều di chuyển xung quanh khái niệm điểm tới hạn .

Trích dẫn từ bài viết của KL Tripp

Điểm bùng phát là gì?

Đó là điểm mà số lượng hàng được trả về là " không còn đủ chọn lọc ". SQL Server chọn KHÔNG sử dụng chỉ mục không phân cụm để tra cứu các hàng dữ liệu tương ứng và thay vào đó thực hiện quét bảng.

Khi SQL Server sử dụng một chỉ mục không được nhóm trên một đống, về cơ bản, nó nhận được một danh sách các con trỏ tới các trang của bảng cơ sở. Sau đó, nó sử dụng các con trỏ này để truy xuất các hàng với một loạt các hoạt động được gọi là Row ID Lookups (RID). Điều này có nghĩa là ít nhất, nó sẽ sử dụng số lượng trang đọc nhiều như số hàng được trả về, và có lẽ nữa. Quá trình này có phần giống với một chỉ mục được nhóm như bảng cơ sở, với cùng kết quả: nhiều lần đọc hơn.

Nhưng, khi điểm tới hạn đó xảy ra?

Tất nhiên, như hầu hết mọi thứ trong cuộc sống này, nó phụ thuộc ...

Không nghiêm trọng, nó xảy ra từ 25% đến 33% số lượng trang trong bảng, tùy thuộc vào số lượng hàng trên mỗi trang. Nhưng có nhiều yếu tố mà bạn nên xem xét:

Trích dẫn từ bài viết của ITPRoToday

Các yếu tố khác ảnh hưởng đến điểm tới hạn Mặc dù chi phí tra cứu RID là yếu tố quan trọng nhất ảnh hưởng đến điểm tới hạn, nhưng có một số yếu tố khác:

  • I / O vật lý hiệu quả hơn nhiều khi quét một chỉ mục cụm. Dữ liệu chỉ mục được nhóm được đặt tuần tự trên đĩa theo thứ tự chỉ mục. Do đó, có rất ít đầu bên di chuyển trên đĩa, giúp cải thiện hiệu năng I / O.
  • Khi công cụ cơ sở dữ liệu đang quét một chỉ mục được nhóm, nó biết rằng có khả năng cao là một vài trang tiếp theo trên rãnh đĩa sẽ vẫn chứa dữ liệu cần thiết. Vì vậy, nó bắt đầu đọc trước trong các đoạn 64KB thay vì các trang 8KB bình thường. Điều này cũng dẫn đến I / O nhanh hơn.

Bây giờ nếu tôi thực hiện lại các truy vấn của mình bằng thống kê IO:

SET STATISTICS IO ON;
SELECT id, foo, bar, nki FROM my_table WHERE nki < 20000 ORDER BY nki ;
SET STATISTICS IO OFF;

Logical reads: 312

SET STATISTICS IO ON;
SELECT id, foo, bar, nki FROM my_table WITH(INDEX(IX_my_TABLE));
SET STATISTICS IO OFF;

Logical reads: 41293

Truy vấn thứ hai cần đọc logic hơn so với truy vấn thứ nhất.

Tôi có nên tránh chỉ số không cụm?

Không, một chỉ mục được nhóm có thể hữu ích, nhưng nó đáng để dành thời gian và nỗ lực thêm để phân tích những gì bạn đang cố gắng đạt được với nó.

Trích dẫn từ bài viết của KL Tripp

Vậy bạn nên làm gì? Nó phụ thuộc. Nếu bạn biết rõ dữ liệu của mình và bạn thực hiện một số thử nghiệm mở rộng, bạn có thể cân nhắc sử dụng một gợi ý (có một số điều thông minh bạn có thể thực hiện theo chương trình trong các sp, tôi sẽ thử và dành một bài đăng này sớm). Tuy nhiên, một lựa chọn tốt hơn nhiều (nếu có thể) là xem xét bảo hiểm (đó thực sự là điểm chính của tôi :). Trong các truy vấn của tôi, che phủ là không thực tế vì các truy vấn của tôi muốn tất cả các cột (CHỌN ác *), nhưng, nếu các truy vấn của bạn hẹp hơn VÀ chúng có mức độ ưu tiên cao, tốt hơn hết là bạn nên sử dụng một chỉ số che phủ (trong nhiều trường hợp) qua một gợi ý vì một chỉ mục bao gồm một truy vấn, không bao giờ mẹo.

Đó là câu trả lời cho câu đố bây giờ nhưng chắc chắn còn rất nhiều điều để đi sâu vào. Điểm tới hạn có thể là một điều rất tốt - và nó thường hoạt động tốt. Nhưng, nếu bạn thấy rằng bạn có thể buộc một chỉ mục và có hiệu suất tốt hơn, bạn có thể muốn thực hiện một số điều tra và xem liệu đó có phải là điều này không. Sau đó xem xét khả năng một gợi ý có thể giúp đỡ và bây giờ bạn biết nơi bạn có thể tập trung.

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.