Kế hoạch thực hiện KHÔNG sử dụng INDEX, Nó sử dụng Quét bảng


9

Tôi biết khi nói đến việc sử dụng một chỉ mục hoặc quét bảng, SQL Server sử dụng số liệu thống kê để xem cái nào tốt hơn.

Tôi có một bảng với 20 triệu hàng. Tôi có một chỉ mục trên (SnapshotKey, Đo lường) và truy vấn này:

select Measure, SnapshotKey, MeasureBand
from t1
where Measure = 'FinanceFICOScore'
group by Measure, SnapshotKey, MeasureBand

Truy vấn trả về 500k hàng. Vì vậy, truy vấn chỉ chọn 2,5% số hàng của bảng.

Câu hỏi đặt ra là tại sao SQL Server không sử dụng chỉ mục không bao gồm mà tôi có và sử dụng quét bảng thay thế?

Thống kê được cập nhật.

Tốt để đề cập rằng hiệu suất truy vấn là tốt mặc dù.

Quét bảng

Quét bảng

Chỉ số cưỡng bức

Chỉ số lực lượng

Cấu trúc bảng / chỉ mục

CREATE TABLE [t1](
    [SnapshotKey] [int] NOT NULL,
    [SnapshotDt] [date] NOT NULL,
    [Measure] [nvarchar](30) NOT NULL,
    [MeasureBand] [nvarchar](30) NOT NULL,
    -- and many more fields
) ON [PRIMARY]

Không có PK trên bàn, vì nó là kho dữ liệu.

CREATE NONCLUSTERED INDEX [nci_SnapshotKeyMeasure] ON [t1]
(
    [SnapshotKey] ASC,
    [Measure] ASC
)

Câu trả lời:


16

Tìm kiếm chỉ mục có thể không phải là lựa chọn tốt nhất nếu bạn trả lại nhiều hàng và / hoặc các hàng rất rộng. Tra cứu có thể tốn kém nếu chỉ số của bạn không bao gồm. Xem # 2 tại đây .

Trong kịch bản của bạn, trình tối ưu hóa truy vấn ước tính rằng việc thực hiện 50.000 lần tra cứu riêng lẻ sẽ tốn kém hơn so với một lần quét. Sự lựa chọn của trình tối ưu hóa giữa quét và tìm kiếm (với tra cứu RID cho các cột cần thiết cho truy vấn, nhưng không có trong chỉ mục không bao gồm) dựa trên chi phí ước tính của mỗi phương án.

Trình tối ưu hóa luôn chọn phương án thay thế chi phí thấp nhất mà nó xem xét. Nếu bạn nhìn vào thuộc tính Chi phí Subtree ước tính trong nút gốc của hai kế hoạch thực hiện, bạn sẽ thấy rằng kế hoạch quét có chi phí ước tính thấp hơn so với kế hoạch tìm kiếm. Kết quả là trình tối ưu hóa đã chọn quét. Đó thực chất là câu trả lời cho câu hỏi của bạn.

Bây giờ, mô hình chi phí được sử dụng bởi trình tối ưu hóa dựa trên các giả định và "số ma thuật" rất khó phù hợp với đặc điểm hiệu suất của hệ thống của bạn. Cụ thể, một giả định được đưa ra trong mô hình là truy vấn bắt đầu thực thi mà không có trang dữ liệu hoặc chỉ mục nào được yêu cầu đã có trong bộ nhớ. Một điều nữa là I / O tuần tự (dự kiến ​​cho một lần quét) rẻ hơn so với mẫu I / O ngẫu nhiên được giả định cho RID Lookups. Có rất nhiều giả định và cảnh báo khác, quá nhiều để đi vào chi tiết ở đây.

Tuy nhiên, toàn bộ mô hình chi phí đã được chứng minh là tạo ra các kế hoạch "đủ tốt" cho hầu hết các truy vấn, trên hầu hết các lược đồ cơ sở dữ liệu, trên hầu hết các cấu hình phần cứng, hầu hết mọi lúc, mọi nơi. Đó là một thành tích khá, nếu bạn nghĩ về nó.

Các hạn chế của mô hình và các yếu tố khác đôi khi sẽ có nghĩa là trình tối ưu hóa chọn một kế hoạch thực tế không "đủ tốt". Bạn báo cáo rằng "hiệu suất là tốt", vì vậy đó dường như không phải là trường hợp ở đây.


9

Bạn thực sự có 595.947 hàng phù hợp, chiếm khoảng 3% dữ liệu của bạn. Vì vậy, chi phí tra cứu tăng lên nhanh chóng. Giả sử bạn có 100 hàng trên mỗi trang trong bảng của mình, đó là 200.000 trang để đọc trong quá trình quét bảng. Đó là rẻ hơn rất nhiều so với làm 595.947 tra cứu.

Với GROUP BYmệnh đề trong câu hỏi, tôi nghĩ bạn sẽ tốt hơn khi sử dụng khóa tổng hợp trên (Số đo, SnapshotKey, Số đo).

Nhìn vào gợi ý "thiếu chỉ số". Nó cho bạn biết bao gồm các cột để tránh tra cứu. Tổng quát hơn, nếu bạn tham chiếu các cột khác trong truy vấn của mình, chúng sẽ cần nằm trong các khóa hoặc INCLUDEmệnh đề của chỉ mục mới. Nếu không, nó vẫn sẽ cần phải thực hiện tra cứu 595.947 để có được các giá trị đó.

Ví dụ: đối với truy vấn:

select Measure, SnapshotKey, MeasureBand, SUM(NumLoans), SUM(PrinBal)
from t1
where Measure = 'FinanceFICOScore'
group by Measure, SnapshotKey, MeasureBand

...Bạn sẽ cần:

CREATE INDEX ixWhatever 
ON t1 (Measure, SnapshotKey, MeasureBand) 
INCLUDE (NumLoans,PrinBal);

6
  1. Trường trong điều kiện WHERE của bạn không phải là trường hàng đầu của chỉ mục.

  2. Bạn đã measurexác định là NVARCHAR để tiền tố bằng chữ N: where Measure = N'FinanceFICOScore'.

Xem xét việc tạo một Chỉ số cụm trên SnapshotKey. Nếu nó là duy nhất thì nó có thể là PK (và Clustered). Nếu không phải là duy nhất thì nó không thể là PK, nhưng vẫn có thể là một Chỉ số cụm không duy nhất. Sau đó, chỉ mục không được nhóm của bạn sẽ chỉ trên measurecột.

Và, xem xét rằng lĩnh vực đầu tiên trong GROUP BYcũng là measure, điều đó cũng sẽ được hưởng lợi từ việc có measuređược lĩnh vực hàng đầu.

Trong thực tế, đối với thao tác này, thay vào đó, bạn có thể cần xác định Chỉ mục NonClustered Measure, SnapshotKey, MeasureBandtheo thứ tự chính xác vì nó phù hợp với GROUP BYmệnh đề. Kích thước khôn ngoan chỉ thực sự được thêm vào MeasureBandvì chỉ mục NonClustered đã được dựa trên MeasureMeasureKeyđã được bao gồm trong chỉ mục vì giờ đây là khóa Chỉ mục cụm (không, Measuresẽ không được sao chép trong chỉ mục NonClustered).

@Rob đã đề cập trong một bình luận hiện đã bị xóa về câu trả lời của anh ấy rằng việc giải quyết vấn đề này chỉ yêu cầu Chỉ số NonClustered được xác định theo ba trường theo thứ tự này và việc tạo Chỉ mục cụm (không duy nhất) trên SnapshotKeylà không cần thiết . Mặc dù anh ta có thể đúng (tôi đã hy vọng rằng ít trường hơn sẽ hoạt động), tôi vẫn cho rằng việc có Chỉ số cụm có lợi cho không chỉ hoạt động này, mà có lẽ hầu hết các lĩnh vực khác.


Các cuộc thảo luận về câu trả lời này đã được chuyển sang trò chuyện .
Paul White 9
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.