查詢優化器建議添加索引而不是使用現有索引
我試圖確定為什麼 SQL Server 中的查詢優化器建議創建一個新索引,而不是使用似乎足以用於查詢的現有索引。
首先是表。更改了列名以保護無辜者:-)
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 ) )
創建有問題的索引:
CREATE NONCLUSTERED INDEX [IDX_myIndex] ON [myTable] ([serialNumber], [sName], [meanValue], [range]) INCLUDE ([modifiedDate])
使用您選擇的生成器添加數據進行測試;-) 執行以下查詢(表只有幾百萬條記錄)
SELECT TOP 1000 [serialNumber], [sName], [meanValue], [range], [modifiedDate] FROM [myTable] WHERE [serialNumber] = 137802 AND [sName] = 'A Name'
查詢優化器建議使用一個新索引,其中附加的 where 子句包含在 INCLUDE 中,而不是鍵的一部分:
CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>] ON [dbo].[myTable] ([sName]) INCLUDE ([serialNumber],[meanValue],[range],[modifiedDate])
我的印像是,只要 WHERE 子句的順序代表索引列的順序,包含更多列的更廣泛的索引將用作索引。
如果我還在 modifiedData 上 WHERE 使用索引並且查詢優化器不會抱怨:
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')
DBA 連結
SQL Server 2008R2 - Why is my index not used表明索引鍵和包含與 SELECT 語句之間的更緊密相關性有助於確定索引的使用(但在我的範例中它們基本相同)。我有很多行,可能滿足行使用機率測試,並且沒有 NULL - 因此否定索引的 NULL 效果。
我認為,也許是錯誤的,索引
A, B, C, D
會覆蓋一個查詢 whereA, B, C
, orA, B
, orA
將被執行。這個假設是錯誤的嗎?我意識到可能存在使這個基本概念失衡的邊緣條件,但從根本上說,這不是大致應該如何工作的嗎?在此先感謝您的幫助,指出我的愚蠢方式,認識到我需要(返回)去 DB 學校等… :-)
您的索引對於查詢來說似乎很好(即覆蓋),應該使用它。真正的問題是查詢本身,特別是隱藏隱式轉換的條件:
WHERE [serialNumber] = 137802
根據 SQL Server 的數據類型優先級,當比較不同數據類型的兩個值時,將優先級較低的數據類型的值轉換為優先級較高的數據類型。不幸的是,
int
在列表中高於varchar
。serialNumber
當列 ( ) 值被轉換為整數時,這會破壞使用索引的任何希望。該列是索引的第一個位置,導致優化器不使用該索引並蒐索替代項(因此是建議。)解決方案是不要對條件中的列進行任何隱式或顯式轉換
WHERE
。只需使用:WHERE [serialNumber] = '137802'