Quy tắc cứng và nhanh để bao gồm các cột trong chỉ mục


38

Có quy tắc cứng và nhanh nào để quyết định cột nào và theo thứ tự nào sẽ được đưa vào Bao gồm trong chỉ mục không được nhóm. Tôi vừa đọc bài đăng này https://stackoverflow.com/questions/1307990/why-use-the-include-clause-when-creating-an-index và tôi thấy rằng cho truy vấn sau:

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

Các poster đề nghị tạo chỉ mục như thế này:

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

đây là câu hỏi của tôi tại sao chúng ta không thể tạo ra chỉ mục như thế này

CREATE NONCLUSTERED INDEX NC_EmpDep 
      ON Employee( EmployeeID, DepartmentID, LastName)

hoặc là

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

và điều gì dẫn đến người đăng quyết định giữ lại cột LastName. Tại sao không phải là cột khác? và làm thế nào để quyết định theo thứ tự chúng ta nên giữ các cột ở đó?


3
BAO GỒM thông thường nên có các trường bạn sẽ cần SAU một bản ghi đã được tìm thấy, tiết kiệm cho bạn một chuyến đi khứ hồi để lấy thêm dữ liệu. Thứ tự của các trường trong INCLUDE không quan trọng.
Jimbo

Ryk, cá nhân tôi thấy bài viết này hữu ích.
Jason Young

Tôi thấy câu hỏi này cũng hữu ích. Hãy tập trung vào những câu hỏi hay và câu trả lời hay thay vì rình rập cá nhân ....
Volvox

Câu trả lời:


47

Đó là gợi ý chỉ số của marc_s là sai. Tôi đã thêm một bình luận. (Và đó là câu trả lời của tôi cũng được chấp nhận!)

Chỉ mục cho truy vấn này sẽ là

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

Một chỉ số thường

CREATE INDEX <name> ON <table> (KeyColList) INCLUDE (NonKeyColList)

Ở đâu:

  • KeyColList = Cột cột = được sử dụng để hạn chế hàng và xử lý
    WHERE, THAM GIA, ĐẶT HÀNG, NHÓM THEO vv
  • NonKeyColList = Cột không khóa = được sử dụng trong CHỌN và tổng hợp (ví dụ SUM (col)) sau khi chọn / hạn chế

+1 - Tôi đồng ý (xem ans của tôi) rằng các chỉ mục mẫu trong OP là vô giá trị cho truy vấn!
JNK

Tuyệt quá! chỉ một điều nữa là cái gì sẽ quyết định thứ tự của KeyColList và NonKeyColList. Bạn có thể giải thích với ví dụ của tôi? Giả sử bây giờ truy vấn của tôi là CHỌN EmployeeID, DepartmentID, LastName TỪ EmployeeWHERE DepartmentID = 5, StateID = 4 Làm thế nào bây giờ là chỉ mục?

@Rocky - NonKeyColListthứ tự không thành vấn đề. KeyColListthứ tự nên theo thứ tự tần suất mà bạn mong đợi chúng sẽ được sử dụng trong các truy vấn. Xem ghi chú của tôi về câu trả lời của tôi dưới đây, nhưng nó giống như Last Name, First Name, Middile Initialtrong một danh bạ điện thoại. Bạn cần trường đầu tiên để tìm trường thứ hai.
JNK

@gbn Chúng tôi có thực sự yêu cầu EmployeeID trong danh sách bao gồm không? Vì nếu chúng ta có một chỉ mục được nhóm trên Cột EmployeeID và trên đầu này nếu chúng ta tạo một chỉ mục không bao gồm trên cột DeptId, thì chỉ mục NonClustered đã tham chiếu đến khóa phân cụm được bao gồm trong cấu trúc Chỉ mục NonClustered, bao gồm cả khóa phân cụm trong danh sách INCLUDE không ' t thêm bất kỳ lợi ích.
Viswanathan Iyer

1
@ViswanathanIyer nó sẽ không được thêm hai lần vào bộ lưu trữ trên đĩa thực tế: SQL Server phát hiện ra điều này. Vì vậy, nó không cần thiết nhưng nó làm cho mọi thứ rõ ràng hơn. Tuy nhiên, chúng tôi không biết về bất kỳ chỉ mục được nhóm nào trong câu hỏi để an toàn hơn khi không sử dụng.
gbn

19

JNK và gbn đã đưa ra câu trả lời tuyệt vời, nhưng cũng đáng để xem xét bức tranh lớn - không chỉ tập trung vào một truy vấn duy nhất. Mặc dù truy vấn cụ thể này có thể được hưởng lợi từ một chỉ mục (# 1):

Employee(DepartmentID) INCLUDE (Lastname, EmployeeID)

Chỉ mục này hoàn toàn không giúp ích gì nếu truy vấn thay đổi một chút, chẳng hạn như:

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5 AND LastName = 'Smith'

Điều này sẽ cần chỉ mục (# 2):

Employee(DepartmentID, LastName) INCLUDE (EmployeeID)

Hãy tưởng tượng bạn có 1.000 nhân viên ở Bộ 5. Sử dụng chỉ số # 1, để tìm tất cả các Smith, bạn cần tìm kiếm trong tất cả 1.000 hàng trong Bộ 5, vì các cột được bao gồm không phải là một phần của khóa. Sử dụng chỉ số # 2, bạn có thể tìm kiếm trực tiếp đến Bộ 5, LastName Smith.

Do đó, Chỉ số 2 hữu ích hơn trong việc phục vụ một phạm vi truy vấn rộng hơn - nhưng chi phí là một khóa chỉ mục cồng kềnh hơn, điều này sẽ làm cho các trang không có lá của chỉ mục lớn hơn. Mỗi hệ thống sẽ khác nhau, vì vậy không có quy tắc nào ở đây.


Một lưu ý phụ, đáng để chỉ ra rằng nếu EmployeeID là khóa phân cụm cho bảng này - giả sử chỉ mục được nhóm - thì bạn không cần đưa EmployeeID - nó có trong tất cả các chỉ mục không được phân cụm, có nghĩa là chỉ số # 2 chỉ có thể được

Employee(DepartmentID, LastName)

2
+1 để biết thêm thông tin hữu ích. Đối với điểm cuối cùng của bạn, tôi đã kiểm tra điều này và việc sử dụng EmployeeID rõ ràng trong INCLUDE thực sự bị bỏ qua (dựa trên kích thước của chỉ mục) nếu EmployeeID là chỉ mục được nhóm. Nó rõ ràng hơn mặc dù tôi nghĩ và không có nhược điểm.
gbn

1
Tôi hoàn toàn đồng ý - luôn luôn tốt hơn để được rõ ràng, đặc biệt là nếu nó không có chi phí!

1
Chỉ trong trường hợp ... Ý tôi là tôi đã kiểm tra khóa cụm trong INCLUDE (không phải EmployeeID một cách rõ ràng) và nó không thêm dung lượng. Trong các cột chính nó làm.
gbn

@gbn Có, khóa cụm chỉ cần nằm ở cấp độ lá của chỉ mục, đó là nơi các cột INCLUDE cư trú. Di chuyển nó vào khóa chỉ mục cũng có nghĩa là nó sẽ tồn tại trong các trang không có lá. Điều này sẽ dẫn đến một chút phình to, nhưng không phải là một số tiền khủng khiếp (trên các trang ở cấp độ trung gian, bạn sẽ thêm 4 byte cho mỗi trang cấp độ lá, giả sử là một Số nguyên).

Đây là câu trả lời tuyệt vời bao gồm một số hiệu ứng được mô tả trong bài viết này: sqlperformance.com/2014/07/sql-indexes/ tựa Nếu truy vấn của bạn thay đổi thì hãy thực hiện các yêu cầu của chỉ mục của bạn. Bạn có thể tốt hơn với câu trả lời của Jim nhưng bạn có thể trả giá tốt hơn với câu trả lời @gbn.
John aka hot2use

7

Tôi không chắc làm thế nào bạn có được cái đầu tiên. Đối với tôi, đối với truy vấn đó, tôi sẽ sử dụng:

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

Không có "quy tắc cứng và nhanh" cho hầu hết mọi thứ trong SQL.

Nhưng, ví dụ của bạn, trường duy nhất mà chỉ mục sẽ sử dụng là DepartmentIDvì nó nằm trong WHEREmệnh đề.

Các lĩnh vực khác chỉ cần có thể dễ dàng truy cập từ đó. Bạn chọn dựa vào DepartmentIDsau đó INCLUDEcó các trường đó tại nút lá của chỉ mục.

Bạn không muốn sử dụng các ví dụ khác của mình vì chúng sẽ không hoạt động cho chỉ mục này.

Hãy nghĩ về một chỉ số như một cuốn sách điện thoại. Hầu hết các danh bạ điện thoại được sắp xếp theo Họ, Tên, Tên đệm ban đầu. Nếu bạn biết tên của ai đó, nhưng không phải họ của họ, danh bạ điện thoại sẽ không tốt vì bạn không thể tìm kiếm tên dựa trên thứ tự của chỉ mục của danh bạ điện thoại.

Các INCLUDEtrường giống như số điện thoại, địa chỉ, vv thông tin khác cho mỗi mục trong sách.

CHỈNH SỬA:

Để làm rõ hơn tại sao không sử dụng:

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

Chỉ số này chỉ hữu ích nếu bạn có EmployeeIDhoặc BÓNG EmployeeIDLastNametrong WHEREmệnh đề của bạn . Đây là khá nhiều OPPOSITE của những gì bạn cần cho truy vấn này.


@ajbeaven đó là sự thật, đó là lý do tại sao bình luận tôi đưa vào chỉnh sửa nói rằng bạn cần EITHER workerID hoặc cả hai cột.
JNK

xin lỗi đã đọc sai :(
ajbeaven

0

Tôi nghĩ rằng bạn vẫn có thể sử dụng chỉ mục (worker_id, Division_id), nhưng bạn phải bao gồm một dòng 'giả' trong cụm từ, như: "worker_id = worker_id)

  • có một chỉ mục trên (worker_id, oblemnent_id),
  • phải tìm kiếm / hạn chế chỉ trên một bộ phận
  • biết rằng nó sẽ không sử dụng chỉ mục vì thứ tự sai (hoặc mọi thứ đã thay đổi và "mẹo" sau đây không còn cần thiết nữa. Tôi là một "người già"?) .
  • Sử dụng tricK "cũ"?

    chọn * từ Empee emp
    nơi emp.employee_id = emp.employee_id
    và emp.depidor_id = 5

(Vì vậy, tôi không tập trung vào phần bao gồm ở đây của Lastname, nhưng về phần có / hoặc không được sử dụng của khóa.)

Trân trọng,

Miguell


2
Không, đó là vô dụng và không hiệu quả.
ypercubeᵀᴹ

Cụ thể, nó vẫn sẽ phải quét chỉ mục để tìm kiếm mọi id nhân viên để tìm tất cả các phiên bản của bộ phận_id 5. Nếu có 1000 nhân viên và 5 phòng ban, SQL phải xem qua tất cả 1000 nhân viên để tìm tất cả các hàng cho một bộ phận cụ thể.
Đánh dấu Sowul

Bây giờ hãy xem xét trường hợp ngược lại (chỉ mục là trên cục_id, worker_id). Rõ ràng bây giờ thật dễ dàng để tìm một bộ phận cụ thể, nhưng cũng lưu ý rằng để tìm một nhân viên cụ thể, SQL chỉ phải quét qua 5 bộ phận để tìm tất cả các hàng cho một nhân viên cụ thể.
Đánh dấu Sowul
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.