Tại sao nên sử dụng mệnh đề INCLUDE khi tạo chỉ mục?


431

Trong khi học cho kỳ thi 70-433 tôi nhận thấy bạn có thể tạo một chỉ số bao phủ theo một trong hai cách sau.

CREATE INDEX idx1 ON MyTable (Col1, Col2, Col3)

-- HOẶC LÀ --

CREATE INDEX idx1 ON MyTable (Col1) INCLUDE (Col2, Col3)

Mệnh đề INCLUDE là mới đối với tôi. Tại sao bạn sẽ sử dụng nó và bạn sẽ đề xuất hướng dẫn nào trong việc xác định có nên tạo chỉ mục bao phủ có hoặc không có mệnh đề INCLUDE?

Câu trả lời:


363

Nếu cột không nằm trong WHERE/JOIN/GROUP BY/ORDER BY, mà chỉ trong danh sách cột trong SELECTmệnh đề.

Các INCLUDEđiều khoản bổ sung các dữ liệu ở mức thấp nhất / lá, chứ không phải trong cây chỉ mục. Điều này làm cho chỉ số nhỏ hơn vì nó không phải là một phần của cây

INCLUDE columnskhông phải là các cột chính trong chỉ mục, vì vậy chúng không được sắp xếp. Điều này có nghĩa là nó không thực sự hữu ích cho các vị từ, sắp xếp, v.v. như tôi đã đề cập ở trên. Tuy nhiên, nó thể hữu ích nếu bạn có một tra cứu còn lại trong một vài hàng từ (các) cột chính

Một bài viết MSDN khác với một ví dụ hoạt động


7
Vì vậy, đây sẽ là một kỹ thuật để tạo ra một phiên bản ít tốn kém hơn của một chỉ số được bảo hiểm?
JMarsch

3
@gbn, bạn có phiền giải thích câu này chi tiết hơn không và giải thích tại sao nó có nghĩa là mệnh đề bao gồm không hữu ích cho việc sắp xếp, v.v .: "Mệnh đề INCLUDE thêm dữ liệu ở mức thấp nhất / lá, thay vì trong cây chỉ mục Điều này làm cho chỉ số nhỏ hơn vì nó không phải là một phần của cây "
Tola Odejayi

4
@JMarsch: xin lỗi vì đã trả lời trễ, nhưng đúng vậy, đây chính xác là những gì nó được.
gbn

10
@Tola Odejayi: INCLUDE cột không phải là cột chính trong chỉ mục, vì vậy chúng không được đặt hàng. Điều này làm cho chúng thường không hữu ích cho THAM GIA hoặc sắp xếp. Và bởi vì chúng không phải là các cột chính, chúng không ngồi trong toàn bộ cấu trúc cây B như các cột chính
gbn

4
Mặc dù đây là câu trả lời được chấp nhận nhiều nhất, tôi nghĩ cần giải thích thêm, nhưng nếu đối với một số truy vấn thì cột là một phần của SELECTvà đối với một số thì không? \
Chisko

215

Bạn sẽ sử dụng INCLUDE để thêm một hoặc nhiều cột vào cấp độ lá của một chỉ mục không được nhóm, nếu làm như vậy, bạn có thể "che" các truy vấn của mình.

Hãy tưởng tượng bạn cần truy vấn ID nhân viên, ID bộ phận và họ.

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5

Nếu bạn tình cờ có một chỉ mục không được nhóm trên (EmployeeID, DepartmentID), một khi bạn tìm thấy các nhân viên cho một bộ phận nhất định, bây giờ bạn phải thực hiện "tra cứu dấu trang" để có được hồ sơ nhân viên thực tế, chỉ để có được cột tên cuối cùng . Điều đó có thể trở nên khá tốn kém về hiệu suất, nếu bạn tìm thấy nhiều nhân viên.

Nếu bạn đã bao gồm họ đó trong chỉ mục của bạn:

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(EmployeeID, DepartmentID)
  INCLUDE (Lastname)

sau đó tất cả thông tin bạn cần có sẵn ở cấp độ lá của chỉ mục không được nhóm. Chỉ cần tìm kiếm trong chỉ mục không được nhóm và tìm nhân viên của bạn cho một bộ phận nhất định, bạn có tất cả thông tin cần thiết và việc tìm kiếm dấu trang cho mỗi nhân viên được tìm thấy trong chỉ mục không còn cần thiết -> bạn tiết kiệm rất nhiều thời gian.

Rõ ràng, bạn không thể bao gồm mọi cột trong mọi chỉ mục không được phân cụm - nhưng nếu bạn có các truy vấn bị thiếu chỉ một hoặc hai cột được "che" (và được sử dụng rất nhiều), thì có thể rất hữu ích để BAO GỒM thành một chỉ số không phân cụm thích hợp.


25
Bạn có chắc chắn bạn sẽ sử dụng chỉ số này? Tại sao nhân viên? Bạn chỉ cần DepartmentID trong các cột chính? Bạn đã được trích dẫn ở đây là có thẩm quyền: stackoverflow.com/q/6187904/27535
gbn

3
Giải thích của bạn là tốt nhưng không thực sự phù hợp với trường hợp sử dụng mà bạn phác thảo. (Các) cột khóa phải nằm trên bộ lọc hoặc JOINcác khóa trong truy vấn và INCLUDEs cần phải là dữ liệu bạn đang truy xuất nhưng không sắp xếp.
JNK

15
Trước hết, chỉ mục Nhân viên (EmployeeID, DepartmentID) sẽ không được sử dụng để lọc DepartmentID = 5. Vì đơn hàng của nó không khớp
AnandPhadke

29

Cuộc thảo luận này đã bỏ lỡ điểm quan trọng: Câu hỏi không phải là "các cột không phải là khóa" tốt hơn để bao gồm dưới dạng chỉ mục- màu hay là bao gồm các màu.

Câu hỏi đặt ra là chi phí đắt đỏ như thế nào khi sử dụng cơ chế bao gồm để bao gồm các cột không thực sự cần thiết trong chỉ mục ? (thường không phải là một phần của mệnh đề where, nhưng thường được bao gồm trong các lựa chọn). Vì vậy, tình trạng khó xử của bạn luôn là:

  1. Sử dụng chỉ mục trên id1, id2 ... idN một mình hoặc
  2. Sử dụng chỉ mục trên id1, id2 ... idN plus bao gồm col1, col2 ... colN

Trong đó: id1, id2 ... idN là các cột thường được sử dụng trong các hạn chế và col1, col2 ... colN là các cột thường được chọn, nhưng thường không được sử dụng trong các hạn chế

(Tùy chọn bao gồm tất cả các cột này như một phần của khóa chỉ mục luôn luôn ngớ ngẩn (trừ khi chúng cũng được sử dụng trong các hạn chế) - vì sẽ luôn tốn kém hơn để duy trì vì chỉ mục phải được cập nhật và sắp xếp ngay cả khi "Phím" không thay đổi).

Vậy sử dụng phương án 1 hay 2?

Trả lời: Nếu bảng của bạn hiếm khi được cập nhật - chủ yếu được chèn vào / xóa khỏi - thì việc sử dụng cơ chế bao gồm một số "cột nóng" (thường được sử dụng trong các lựa chọn - nhưng thường không được sử dụng trong các hạn chế) chèn / xóa yêu cầu chỉ mục phải được cập nhật / sắp xếp và do đó ít chi phí phụ có liên quan đến việc lưu trữ một vài cột bổ sung trong khi đã cập nhật chỉ mục. Chi phí hoạt động là bộ nhớ thêm và CPU được sử dụng để lưu trữ thông tin dư thừa trên chỉ mục.

Nếu các cột bạn xem xét để thêm vào như các cột được bao gồm thường được cập nhật (không có các chỉ số khóa màu được cập nhật) - hoặc - nếu có quá nhiều trong số chúng thì chỉ mục sẽ gần với một bản sao của bảng của bạn - sử dụng tùy chọn 1 Tôi muốn đề nghị! Ngoài ra, nếu việc thêm một số cột bao gồm không tạo ra sự khác biệt về hiệu suất - bạn có thể muốn bỏ qua ý tưởng thêm chúng :) Xác minh rằng chúng hữu ích!

Số lượng hàng trung bình trên mỗi giá trị giống nhau trong các khóa (id1, id2 ... idN) cũng có thể có tầm quan trọng.

Lưu ý rằng nếu một cột - được thêm dưới dạng một chỉ số bao gồm - được sử dụng trong hạn chế : Miễn là chỉ mục đó có thể được sử dụng (dựa trên hạn chế đối với chỉ mục- khóa-khóa ) - thì SQL Server phù hợp hạn chế cột đối với chỉ mục (giá trị nút-lá) thay vì đi theo cách đắt tiền xung quanh bảng.


18

Các cột chỉ mục cơ bản được sắp xếp, nhưng các cột bao gồm không được sắp xếp. Điều này giúp tiết kiệm tài nguyên trong việc duy trì chỉ mục, trong khi vẫn có thể cung cấp dữ liệu trong các cột được bao gồm để bao gồm một truy vấn. Vì vậy, nếu bạn muốn bao gồm các truy vấn, bạn có thể đặt tiêu chí tìm kiếm để định vị các hàng vào các cột được sắp xếp của chỉ mục, nhưng sau đó "bao gồm" các cột bổ sung, chưa được sắp xếp với dữ liệu không tìm kiếm. Nó chắc chắn giúp giảm số lượng phân loại và phân mảnh trong bảo trì chỉ mục.


7

Những lý do tại sao (bao gồm dữ liệu ở cấp độ lá của chỉ số) đã được giải thích độc đáo. Lý do mà bạn đưa ra hai lần lắc về điều này là vì khi bạn chạy truy vấn của mình, nếu bạn không có các cột bổ sung đi kèm (tính năng mới trong SQL 2005), SQL Server phải đi đến chỉ mục được nhóm để lấy các cột bổ sung việc này tốn nhiều thời gian hơn và tăng thêm tải cho dịch vụ SQL Server, các đĩa và bộ nhớ (cụ thể là bộ đệm đệm) khi các trang dữ liệu mới được tải vào bộ nhớ, có khả năng đẩy dữ liệu cần thiết khác ra khỏi bộ đệm.


Có cách nào để chứng minh rằng nó thực sự sử dụng ít bộ nhớ hơn không? đó cũng là những gì tôi mong đợi nhưng tôi sẽ hiểu được điều này tại nơi làm việc
Asken

Cho rằng bạn phải tải trang từ chỉ mục heap hoặc clustered vào bộ nhớ cũng như trang chỉ mục, điều đó có nghĩa là bạn đang đưa dữ liệu trùng lặp vào bộ nhớ, toán học trở nên khá đơn giản. Đối với một cách để đo lường cụ thể, không có.
mrdenny

5

Một xem xét bổ sung mà tôi chưa thấy trong các câu trả lời đã được đưa ra, đó là các cột được bao gồm có thể thuộc loại dữ liệu không được phép dưới dạng cột khóa chỉ mục, chẳng hạn như varchar (max).

Điều này cho phép bạn bao gồm các cột như vậy trong một chỉ mục bao phủ. Gần đây tôi đã phải làm điều này để cung cấp một truy vấn được tạo bởi nHibernate, có rất nhiều cột trong CHỌN, với một chỉ mục hữu ích.


3

Một lý do để thích INCLUDEhơn các cột khóa nếu bạn không cần cột đó trong khóa là tài liệu. Điều đó làm cho việc phát triển các chỉ số dễ dàng hơn nhiều trong tương lai.

Xem xét ví dụ của bạn:

CREATE INDEX idx1 ON MyTable (Col1) INCLUDE (Col2, Col3)

Chỉ mục đó là tốt nhất nếu truy vấn của bạn trông như thế này:

SELECT col2, col3
  FROM MyTable
 WHERE col1 = ...

Tất nhiên, bạn không nên đặt các cột vào INCLUDEnếu bạn có thể nhận được một lợi ích bổ sung từ việc có chúng trong phần chính. Cả hai truy vấn sau đây thực sự sẽ thích col2cột trong khóa của chỉ mục.

SELECT col2, col3
  FROM MyTable
 WHERE col1 = ...
   AND col2 = ...
SELECT TOP 1 col2, col3
  FROM MyTable
 WHERE col1 = ...
 ORDER BY col2

Chúng ta hãy giả sử rằng đây không phải là trường hợp và chúng ta có col2trong INCLUDEmệnh đề bởi vì không có lợi ích gì khi có nó trong phần cây của chỉ mục.

Nhanh chóng chuyển tiếp một số năm.

Bạn cần điều chỉnh truy vấn này:

SELECT TOP 1 col2
  FROM MyTable
 WHERE col1 = ...
 ORDER BY another_col

Để tối ưu hóa truy vấn đó, chỉ mục sau sẽ rất tuyệt:

CREATE INDEX idx1 ON MyTable (Col1, another_col) INCLUDE (Col2)

Nếu bạn kiểm tra những chỉ mục nào bạn có trên bảng đó, chỉ mục trước đó của bạn vẫn có thể ở đó:

CREATE INDEX idx1 ON MyTable (Col1) INCLUDE (Col2, Col3)

Bây giờ bạn biết rằng Col2Col3không phải là một phần của cây chỉ mục và do đó không được sử dụng để thu hẹp phạm vi chỉ mục đọc cũng như để sắp xếp các hàng. Là khá an toàn để thêm another_columnvào cuối phần chính của chỉ mục (sau col1). Có rất ít rủi ro để phá vỡ bất cứ điều gì:

DROP INDEX idx1 ON MyTable;
CREATE INDEX idx1 ON MyTable (Col1, another_col) INCLUDE (Col2, Col3);

Chỉ số đó sẽ trở nên lớn hơn, vẫn còn một số rủi ro, nhưng nói chung là tốt hơn để mở rộng các chỉ mục hiện có so với việc giới thiệu các chỉ số mới.

Nếu bạn có một chỉ mục mà không có INCLUDE, bạn không thể biết những truy vấn nào bạn sẽ phá vỡ bằng cách thêm another_colngay sau đó Col1.

CREATE INDEX idx1 ON MyTable (Col1, Col2, Col3)

Điều gì xảy ra nếu bạn thêm another_colgiữa Col1Col2? Các truy vấn khác sẽ bị?

Có những "lợi ích" khác INCLUDEso với các cột chính nếu bạn thêm các cột đó chỉ để tránh tìm nạp chúng từ bảng . Tuy nhiên, tôi coi khía cạnh tài liệu là quan trọng nhất.

Để trả lời câu hỏi của bạn:

hướng dẫn nào bạn muốn đề xuất trong việc xác định có nên tạo chỉ mục bao phủ có hoặc không có mệnh đề INCLUDE?

Nếu bạn thêm một cột vào chỉ mục cho mục đích duy nhất là có sẵn cột đó trong chỉ mục mà không cần truy cập vào bảng, hãy đặt nó vào INCLUDEmệnh đề.

Nếu việc thêm cột vào khóa chỉ mục mang lại lợi ích bổ sung (ví dụ: order byhoặc vì nó có thể thu hẹp phạm vi chỉ mục đọc), hãy thêm nó vào khóa.

Bạn có thể đọc một cuộc thảo luận dài hơn về điều này ở đây:

https://use-the-index-luke.com/blog/2019-04/include-columns-in-btree-indexes


2

Có giới hạn cho tổng kích thước của tất cả các cột được định nghĩa trong định nghĩa chỉ mục. Mặc dù vậy, tôi chưa bao giờ phải tạo ra chỉ số rộng như vậy. Đối với tôi, lợi thế lớn hơn là bạn có thể bao quát nhiều truy vấn hơn với một chỉ mục bao gồm các cột vì chúng không phải được xác định theo bất kỳ thứ tự cụ thể nào. Hãy suy nghĩ về như là một chỉ số trong chỉ mục. Một ví dụ sẽ là StoreID (trong đó StoreID có độ chọn lọc thấp nghĩa là mỗi cửa hàng được liên kết với rất nhiều khách hàng) và sau đó dữ liệu nhân khẩu học của khách hàng (LastName, FirstName, DOB): Nếu bạn chỉ nội tuyến các cột đó theo thứ tự này (StoreID, LastName , FirstName, DOB), bạn chỉ có thể tìm kiếm khách hàng một cách hiệu quả mà bạn biết StoreID và LastName.

Mặt khác, việc xác định chỉ mục trên StoreID và bao gồm các cột LastName, FirstName, DOB sẽ cho phép bạn thực hiện hai biến vị ngữ chỉ mục trên StoreID và sau đó tìm kiếm vị từ trên bất kỳ cột nào được bao gồm. Điều này sẽ cho phép bạn bao gồm tất cả các hoán vị tìm kiếm có thể miễn là nó bắt đầu với StoreID.

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.