Tìm kiếm chỉ mục vs Quét chỉ mục


64

Nhìn vào một kế hoạch thực hiện của một truy vấn chạy chậm và tôi nhận thấy rằng một số nút được tìm kiếm chỉ mục và một số trong số chúng là quét chỉ mục.

Sự khác biệt giữa tìm kiếm và chỉ mục và quét chỉ mục là gì?

Cái nào thực hiện tốt hơn?

Làm thế nào để SQL chọn cái này hơn cái kia?

Tôi nhận ra đây là 3 câu hỏi nhưng tôi nghĩ trả lời câu hỏi đầu tiên sẽ giải thích cho những người khác.


6
Bạn có một tài liệu tham khảo tốt về use-the-index-luke .
Mary

7
Không phải tất cả các lần quét đều xấu - đôi khi đó là cách hiệu quả nhất để đáp ứng truy vấn. Cũng lưu ý rằng không phải tất cả các tìm kiếm đều là tìm kiếm - thường chúng thực sự là quét phạm vi và tìm kiếm chỉ cho biết làm thế nào nó bắt đầu phạm vi.
Aaron Bertrand

@AaronBertrand nhưng nếu nó bắt đầu phạm vi và đọc nó, về cơ bản, điều đó có nghĩa là bạn vẫn cần dữ liệu. Ngoài ra, nó tìm kiếm sự kết thúc của phạm vi.
George Polevoy

Câu trả lời:


76

Phiên bản ngắn: tìm kiếm tốt hơn nhiều

Phiên bản ngắn hơn: tìm kiếm thường tốt hơn nhiều, nhưng rất nhiều tìm kiếm (gây ra bởi thiết kế truy vấn xấu với các truy vấn phụ tương quan khó chịu hoặc do bạn đang thực hiện nhiều truy vấn trong thao tác con trỏ hoặc vòng lặp khác) có thể tệ hơn một quét, đặc biệt nếu truy vấn của bạn có thể sẽ trả về dữ liệu từ hầu hết các hàng trong bảng bị ảnh hưởng.

Nó giúp bao quát cả gia đình cho các hoạt động tìm kiếm dữ liệu để hiểu đầy đủ ý nghĩa hiệu suất.

Quét bảng: Không có chỉ mục nào liên quan đến truy vấn của bạn, trình hoạch định buộc phải sử dụng quét bảng có nghĩa là mọi hàng được xem xét. Điều này có thể dẫn đến mọi trang liên quan đến dữ liệu của bảng được đọc từ đĩa thường là trường hợp xấu nhất. Lưu ý rằng đối với một số truy vấn, nó sẽ sử dụng quét bảng ngay cả khi có chỉ mục hữu ích - điều này thường là do dữ liệu trong bảng quá nhỏ nên sẽ gặp nhiều rắc rối hơn khi đi qua các chỉ mục (nếu đây là trường hợp bạn mong đợi có kế hoạch thay đổi khi dữ liệu tăng lên, giả sử thước đo chọn lọc của chỉ số là tốt).

Quét chỉ mục với tra cứu hàng: Không tìm thấy chỉ mục nào có thể được sử dụng trực tiếp cho tìm kiếm nhưng chỉ mục chứa các cột bên phải sẽ xuất hiện quét chỉ mục. Ví dụ: nếu bạn có một bảng lớn có 20 cột với chỉ mục trên cột1, col2, col3 và bạn phát hành SELECT col4 FROM exampletable WHERE col2=616, trong trường hợp này, quét chỉ mục để truy vấn col2sẽ tốt hơn quét toàn bộ bảng. Khi các hàng khớp được tìm thấy thì các trang dữ liệu cần được đọc để lấy col4 cho đầu ra (hoặc tham gia thêm), đó là giai đoạn "tra cứu dấu trang" khi bạn nhìn thấy nó trong các kế hoạch truy vấn.

Quét chỉ mục mà không cần tra cứu hàng: Nếu ví dụ trên SELECT col1, col2, col3 FROM exampletable WHERE col2=616là không cần nỗ lực thêm để đọc các trang dữ liệu: một khi col2=616tìm thấy các hàng chỉ mục phù hợp với tất cả các dữ liệu được yêu cầu. Đây là lý do tại sao đôi khi bạn thấy các cột sẽ không bao giờ được tìm kiếm, nhưng có khả năng được yêu cầu đầu ra, được thêm vào cuối chỉ mục - nó có thể lưu tra cứu hàng. Khi thêm các cột vào một chỉ mục vì lý do này và chỉ vì lý do này, hãy thêm chúng vào INCLUDEmệnh đề để nói với công cụ rằng nó không cần tối ưu hóa bố cục chỉ mục để truy vấn dựa trên các cột này (điều này có thể tăng tốc các cập nhật được thực hiện cho các cột đó) . Quét chỉ mục có thể là kết quả của các truy vấn không có mệnh đề lọc: SELECT col2 FROM exampletablesẽ quét chỉ mục ví dụ này thay vì các trang bảng.

Tìm kiếm chỉ mục (có hoặc không có tra cứu hàng) : Trong tìm kiếm, không phải tất cả các chỉ mục đều được xem xét. Đối với truy SELECT * FROM exampletable WHERE c1 BETWEEN 1234 AND 4567vấn, công cụ truy vấn có thể tìm thấy hàng đầu tiên sẽ khớp bằng cách thực hiện tìm kiếm dựa trên cây trên chỉ mục trên c1đó sau đó nó có thể điều hướng chỉ mục theo thứ tự cho đến khi đến cuối phạm vi (điều này giống với truy vấn cho c1=1234là có thể có nhiều hàng phù hợp với điều kiện ngay cả đối với một =hoạt động). Điều này có nghĩa là chỉ cần đọc các trang chỉ mục có liên quan (cộng với một vài trang cần thiết cho tìm kiếm ban đầu) thay vì mỗi trang trong chỉ mục (hoặc bảng).

Các chỉ mục được nhóm: Với một chỉ mục được nhóm, dữ liệu bảng được lưu trữ trong các nút lá của chỉ mục đó thay vì nằm trong một cấu trúc heap riêng. Điều này có nghĩa là sẽ không bao giờ cần phải có thêm bất kỳ tra cứu hàng nào sau khi tìm các hàng bằng chỉ mục đó bất kể cột nào là cần thiết [trừ khi bạn có dữ liệu ngoài trang như TEXTcột hoặc VARCHAR(MAX)cột chứa dữ liệu dài].

Bạn chỉ có thể có một chỉ mục được nhóm vì lý do này [1] , chỉ mục được nhóm bảng của bạn thay vì có cấu trúc heap riêng, vì vậy nếu bạn sử dụng một [2], hãy chọn nơi bạn đặt nó cẩn thận để đạt được mức tăng tối đa.

Cũng lưu ý rằng chỉ mục được phân cụm vì "khóa phân cụm" cho bảng và được bao gồm trong mọi chỉ mục không phân cụm trên bảng, do đó, một chỉ mục phân cụm rộng thường không phải là một ý tưởng hay.

[1] Trên thực tế, bạn có thể có nhiều chỉ mục được phân cụm một cách hiệu quả bằng cách xác định các chỉ mục không phân cụm bao gồm hoặc bao gồm mọi cột trên bảng, nhưng điều này có thể gây lãng phí không gian có tác động hiệu suất ghi vì vậy nếu bạn cân nhắc thực hiện thì hãy đảm bảo bạn thực sự cần

[2] Khi tôi nói "nếu bạn sử dụng một chỉ mục được nhóm", xin lưu ý rằng thông thường bạn nên có một bảng trên mỗi bảng. Có các trường hợp ngoại lệ như với tất cả các quy tắc ngón tay cái, các bảng chỉ nhìn thấy ít hơn là chèn số lượng lớn và đọc không theo thứ tự (bảng phân tầng cho các quy trình ETL có lẽ) là ví dụ phổ biến nhất.

Điểm bổ sung: Quét chưa hoàn thành:

Điều quan trọng cần nhớ là tùy thuộc vào phần còn lại của truy vấn, quét bảng / chỉ mục có thể không thực sự quét toàn bộ bảng - nếu logic cho phép kế hoạch truy vấn có thể khiến nó hủy bỏ sớm. Ví dụ đơn giản nhất về điều này là SELECT TOP(1) * FROM HugeTable- nếu bạn nhìn vào kế hoạch truy vấn, bạn sẽ thấy rằng chỉ có một hàng được trả về từ quá trình quét và nếu bạn xem số liệu thống kê IO ( SET STATISTICS IO ON; SELECT TOP(1) * FROM HugeTable) bạn sẽ thấy rằng nó chỉ đọc một số rất nhỏ của các trang (có lẽ chỉ là một).

Điều tương tự có thể xảy ra nếu vị từ của mệnh đề WHEREhoặc JOIN ... ONmệnh đề có thể được chạy đồng thời với quá trình quét là nguồn nếu dữ liệu của nó. Trình lập kế hoạch truy vấn / người chạy đôi khi có thể rất thông minh về việc đẩy các vị từ quay trở lại các nguồn dữ liệu để cho phép chấm dứt sớm các lần quét theo cách này (và đôi khi bạn có thể khéo léo sắp xếp lại các truy vấn để giúp thực hiện điều đó!). Mặc dù dữ liệu chảy từ phải sang trái theo các mũi tên trong màn hình kế hoạch truy vấn tiêu chuẩn, logic chạy từ trái sang phải và mỗi bước (từ phải sang trái) không nhất thiết phải chạy để hoàn thành trước khi bước tiếp theo có thể bắt đầu. Trong ví dụ đơn giản ở trên nếu bạn xem từng khối trong kế hoạch truy vấn như một tác nhân, SELECTtác nhân sẽ hỏi TOPtác nhân đó một hàng, lần lượt hỏiTABLE SCANĐại lý cho một, sau đó SELECTđại lý yêu cầu một đại lý khác nhưng TOPđại lý biết rằng không cần phải không hỏi người đọc bảng, SELECTđại lý nhận được phản hồi "không còn phù hợp" và biết tất cả công việc đã được thực hiện. Nhiều hoạt động chặn loại này tối ưu hóa các quá trình như vậy thường trong các ví dụ phức tạp hơn một bảng / index quét thực sự không đọc từng hàng, nhưng phải cẩn thận không để nhảy đến kết luận rằng bất kỳ quét phải là một hoạt động tốn kém.


6

Nói chung, tìm kiếm là tốt, quét là xấu.

Tìm kiếm là nơi truy vấn có thể sử dụng chỉ mục hiệu quả và sử dụng nó để tìm các hàng cần thiết.

Quét là nơi truy vấn đang xem qua toàn bộ chỉ mục cố gắng tìm những gì nó cần.

SQL chọn như thế nào? Đi sâu vào nội bộ của trình tối ưu hóa truy vấn, quyết định được đưa ra dựa trên truy vấn của bạn và các chỉ mục có sẵn và thông tin thống kê được liên kết với các chỉ mục đó.

Có một vài cuốn sách để đọc có thể được quan tâm ở đây - Cả hai từ hiệu sách Red-Gate tại http://www.red-gate.com/community/books/

  • Kế hoạch thực thi máy chủ SQL của Grant Fritchey
  • Bên trong Trình tối ưu hóa truy vấn của Benjamin Nevarez
  • Thống kê máy chủ SQL của Holger Schmeling

7
Đối với cùng một kế hoạch, một lần quét bảng là tốt, một triệu lượt tìm kiếm là xấu. Vì vậy, tuyên bố đầu tiên của bạn không hoàn toàn chính xác.
Mary

Thật vậy, tìm kiếm chỉ mục và quét chỉ mục đều có cách sử dụng riêng, bạn không thể nói cái này tốt hơn cái khác mà KHÔNG CÓ bối cảnh của các bảng và truy vấn cơ bản. Hầu hết thời gian, nếu một bảng có số liệu thống kê không chính xác, kế hoạch thực hiện có thể được đưa ra dưới dạng tối ưu phụ, chẳng hạn như tìm kiếm chỉ mục bị chọn nhầm trong quá trình quét chỉ mục và ngược lại.
jyao

5

Nếu bạn muốn khai thác chủ đề, một cuốn sách rất hữu ích (ít nhất là đối với tôi) là Kế hoạch thực thi máy chủ SQL của Grant Fritchey, có sẵn miễn phí tại RedGate tại đây .

Nếu bạn có một truy vấn như

SELECT *
FROM myTable

SQL Server có thể sẽ sử dụng quét Index, vì nó cần đi qua tất cả các hàng để hiển thị kết quả được yêu cầu.

Trái lại,

SELECT *
FROM myTable
WHERE myID = 1

chắc chắn sẽ dẫn đến một tìm kiếm Index. SQL Server sẽ sử dụng cấu trúc cây B của chỉ mục myID và việc truy xuất dòng thích hợp sẽ nhanh hơn nhiều.


Tôi không biết liệu mình có đồng ý với "chắc chắn" hay không - ngay cả khi chỉ mục có myID là cột hàng đầu, tìm kiếm có thể không phải là câu trả lời tối ưu (phụ thuộc vào rất nhiều điều, chẳng hạn như liệu nó có phải là duy nhất hay không - có thể là đúng trong bảng khách hàng nhưng không đúng với ID khách hàng trong bảng đơn hàng, có bao nhiêu cột cần được bảo hiểm nhưng không có trong chỉ mục, v.v.).
Aaron Bertrand

Tôi không nghĩ câu trả lời này thực sự bao gồm các câu hỏi được đặt ra.
Zero3

5

Những người khác đã xác định đủ sự khác biệt giữa tìm kiếm và quét. Trong trường hợp này, chính truy vấn của bạn và trình hoạch định thực thi sẽ cung cấp cho bạn thông tin bạn cần để xem giá trị nào được sử dụng làm vị ngữ (bộ lọc) cho truy vấn trong mỗi phần. Thông thường, đó là một cách tốt để luôn luôn thêm các chỉ mục không được nhóm vào các khóa ngoại và tùy thuộc vào các trường hợp sử dụng trong mã chương trình, bạn có thể muốn xem xét việc tạo thêm các chỉ mục nhiều cột hoặc bao gồm các chỉ mục cột. Với thuật ngữ được trình bày ở đây, một tìm kiếm google sẽ cho kết quả tốt trên các ví dụ trên mỗi ví dụ.

Nhưng ví dụ, giả sử mã của bạn đang truy vấn Cột A và Cột B trên các bộ lọc đã cho, nhưng bạn cũng muốn trả về các giá trị của Cột C và Cột E, bạn có thể muốn tạo một chỉ mục trên Cột A và B bằng INCLUDE tùy chọn chứa Cột C và E. Bằng cách đó, một tìm kiếm chỉ mục sẽ trả về mọi thứ bạn cần, vì không cần phải tra cứu để lấy các giá trị khác (C và E) trên cùng một hà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.