Sql-Server

查詢優化器建議添加索引而不是使用現有索引

  • October 29, 2014

我試圖確定為什麼 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會覆蓋一個查詢 where A, B, C, or A, B, orA將被執行。這個假設是錯誤的嗎?我意識到可能存在使這個基本概念失衡的邊緣條件,但從根本上說,這不是大致應該如何工作的嗎?

在此先感謝您的幫助,指出我的愚蠢方式,認識到我需要(返回)去 DB 學校等… :-)

您的索引對於查詢來說似乎很好(即覆蓋),應該使用它。真正的問題是查詢本身,特別是隱藏隱式轉換的條件:

WHERE [serialNumber] = 137802

根據 SQL Server 的數據類型優先級,當比較不同數據類型的兩個值時,將優先級較低的數據類型的值轉換為優先級較高的數據類型。不幸的是,int在列表中高於varcharserialNumber當列 ( ) 值被轉換為整數時,這會破壞使用索引的任何希望。該列是索引的第一個位置,導致優化器不使用該索引並蒐索替代項(因此是建議。)

解決方案是不要對條件中的列進行任何隱式或顯式轉換WHERE。只需使用:

WHERE [serialNumber] = '137802'

引用自:https://dba.stackexchange.com/questions/81324