Trình tối ưu hóa truy vấn khuyên bạn nên thêm chỉ mục thay vì sử dụng chỉ mục hiện có


7

Tôi đang cố gắng xác định lý do tại sao trình tối ưu hóa truy vấn trong SQL Server khuyên bạn nên tạo một chỉ mục mới thay vì sử dụng một chỉ mục hiện có dường như là đủ cho truy vấn.

Đầu tiên là bàn. Tên cột thay đổi để bảo vệ người vô tội :-)

CREATE TABLE [myTable] (
  [id] [int] IDENTITY(1,1) NOT NULL,
  [serialNumber] [varchar](12) NOT NULL,
  [sName] [varchar](64) NOT NULL,
  [meanValue] [int] NOT NULL,
  [range] [int] NOT NULL,
  [modifiedDate] [datetime] NOT NULL,
  CONSTRAINT [PK_myTable] PRIMARY KEY CLUSTERED ( [id] ASC )
)

Tạo chỉ mục trong câu hỏi:

CREATE NONCLUSTERED INDEX [IDX_myIndex]
ON [myTable] ([serialNumber], [sName], [meanValue], [range])
INCLUDE ([modifiedDate])

Thêm dữ liệu để kiểm tra bằng trình tạo lựa chọn của bạn ;-) Chạy truy vấn sau (bảng chỉ có vài triệu bản ghi)

SELECT TOP 1000
  [serialNumber],
  [sName],
  [meanValue],
  [range],
  [modifiedDate]
FROM [myTable]
WHERE [serialNumber] = 137802
AND [sName] = 'A Name'

Trình tối ưu hóa truy vấn khuyên bạn nên sử dụng một chỉ mục mới trong đó bổ sung trong đó các mệnh đề được trình bày trong INCLUDE thay vì một phần của khóa:

CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[myTable] ([sName])
INCLUDE ([serialNumber],[meanValue],[range],[modifiedDate])

Tôi có ấn tượng rằng một chỉ mục rộng hơn bao gồm nhiều cột hơn sẽ được sử dụng làm chỉ mục miễn là thứ tự của các mệnh đề WHERE thể hiện thứ tự của các cột được lập chỉ mục.

Nếu tôi cũng WHERE trên sửa đổiData, chỉ mục sẽ được sử dụng và trình tối ưu hóa truy vấn không phàn nàn:

SELECT TOP 1000
  [serialNumber],
  [sName],
  [meanValue],
  [range],
  [modifiedDate]
FROM [myTable]
WHERE [serialNumber] = 137802
AND [sName] = 'A Name'
AND ([modifiedDate] >= '2000-04-25' AND [modifiedDate] < '2019-04-30') 

Liên kết DBA
SQL Server 2008R2 - Tại sao chỉ mục của tôi không được sử dụng cho thấy mối tương quan chặt chẽ hơn giữa khóa chỉ mục và bao gồm với câu lệnh SELECT giúp xác định sử dụng chỉ mục (nhưng trong ví dụ của tôi về cơ bản là giống nhau). Tôi có rất nhiều hàng, có thể thỏa mãn kiểm tra xác suất sử dụng hàng và không có NULL - do đó phủ nhận hiệu ứng NULL của chỉ mục.

Tôi nghĩ, có thể không chính xác, rằng một chỉ mục A, B, C, Dsẽ bao gồm một truy vấn trong đó A, B, C, hoặc A, B, hoặc Asẽ được chạy. Là giả định này sai? Tôi nhận ra rằng có thể có những điều kiện cạnh tranh để loại bỏ khái niệm cơ bản này, nhưng ở mức độ cơ bản, đây không phải là cách nó hoạt động?

Cảm ơn trước bất kỳ sự giúp đỡ nào, chỉ ra sự ngu ngốc theo cách của tôi, nhận ra tôi cần phải quay lại trường DB, v.v ... :-)


3
Có một sự khác biệt khá lớn, cột khóa hàng đầu trong một chỉ mục là SerialNumbervà chỉ số khác là sName. Ngoài ra, đối với các trường hợp hai chỉ mục có thể thỏa mãn một truy vấn như nhau và trong đó các chỉ mục về cơ bản có cùng kích thước, thì về cơ bản, đó là một xu lật cho SQL Server. Việc nó đề xuất một chỉ mục khác có lẽ có nghĩa là nó có thể đã sử dụng một kế hoạch khác (đây chỉ là một nhận xét vì tôi chưa xem xét chi tiết thực tế hoặc cố gắng để chế lại kịch bản của bạn).
Aaron Bertrand

Bạn giả định về việc liệu chỉ số sẽ được bảo hiểm hay không là một giả định chính xác. Nhưng như ông Bertrand đang nói, Cardinality của serialNumber vs sName có thể làm cho một chỉ mục hữu ích hơn nhiều cho một truy vấn nhất định so với một truy vấn khác, ngay cả khi cả hai chỉ mục bao gồm truy vấn.
mskinner

Bạn cũng có thể làm rõ? Bỏ qua các khuyến nghị, là IDX_myIndexkhông sử dụng? Kế hoạch truy vấn thực tế là gì?
ypercubeᵀᴹ

Bạn cũng có WHERE [serialNumber] = 137802trong khi cột là một varchar. Tôi cá rằng đó là lý do cho những lời phàn nàn.
ypercubeᵀᴹ

2
Tại sao là serialNumbermột varchartrong những nơi đầu tiên nếu các giá trị nó chứa được số? Nếu nó luôn lưu trữ các giá trị số và các số 0 đứng đầu không đáng kể thì việc lưu trữ dưới dạng một kiểu số sẽ gọn hơn.
Martin Smith

Câu trả lời:


14

Chỉ mục của bạn có vẻ tốt và tốt (nghĩa là bao trùm) cho truy vấn và nó nên được sử dụng. Vấn đề thực sự là chính truy vấn và cụ thể là điều kiện này ẩn một chuyển đổi ngầm định:

WHERE [serialNumber] = 137802

Theo ưu tiên kiểu dữ liệu của SQL Server , khi so sánh hai giá trị của các kiểu dữ liệu khác nhau, giá trị với kiểu dữ liệu có mức độ ưu tiên thấp hơn được chuyển đổi thành kiểu dữ liệu có mức độ ưu tiên cao hơn. Thật không may, intlà cao hơn trong danh sách hơn varchar. Điều này thổi bùng mọi hy vọng sử dụng chỉ mục khi các serialNumbergiá trị cột ( ) được chuyển đổi thành số nguyên. Cột là vị trí đầu tiên của chỉ mục, dẫn đến trình tối ưu hóa không sử dụng chỉ mục đó và tìm kiếm một giải pháp thay thế (và do đó là gợi ý.)

Giải pháp là không có bất kỳ chuyển đổi ngầm định hoặc rõ ràng nào của các cột trong WHEREđiều kiện. Đơn giản chỉ cần sử dụng:

WHERE [serialNumber] = '137802'

1
Cảm ơn! Giám sát nhỏ là kết quả của việc chỉ sử dụng dữ liệu số để kiểm tra khi trường serialNumber có thể chứa các ký tự alpha. Bởi vì cuộc gọi từ .Net đang gói tất cả các giá trị mà điều này có thể chưa từng thấy trong sản xuất, nhưng lỗi ngu ngốc trong phần kiểm tra của tôi đã giúp tôi tìm hiểu điều gì đó mới về chỉ mục và chuyển đổi rõ ràng! Cảm ơn bạn!
Hooligancat
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.