Sql-Server

為什麼不使用此日期時間索引?

  • April 20, 2020

我有一張這樣的桌子:

CREATE TABLE TestTable
(
   [TestTableID] [int] IDENTITY(1,1) NOT NULL,
   [IntField1] [int] NOT NULL,
   [IntField2] [int] NOT NULL,
   [IntField3] [int] NOT NULL,
   [IntField4] [int] NOT NULL,
   [IntField5] [int] NOT NULL,
   [DateField1] [datetime] NOT NULL,
   [IntField6] [int] NOT NULL,
   [IntField7] [int] NOT NULL,
   [TextField1] [nvarchar](300) NULL,
   [DateField2] [datetime] NULL,
   [TextField2] [nvarchar](300) NULL,
   [DateField3] [datetime] NULL,
   [BoolField1] [bit] NULL
)

我創建了一個這樣的索引:

CREATE NONCLUSTERED INDEX IX_TestTable_DateField1
ON TestTable(DateField1);

現在我有這個查詢:

   DECLARE @startDate DATETIME = '20190101'
         , @endDate   DATETIME = '20200101'

   SELECT [TestTableID], 
          [IntField1], 
          [IntField2], 
          [IntField3], 
          [IntField4], 
          [IntField5], 
          [DateField1], 
          [IntField6], 
          [IntField7], 
          [TextField1], 
          [DateField2], 
          [TextField2],
          [DateField3], 
          [BoolField1]
     FROM TestTable
    WHERE DateField1 >= @startDate
      AND DateField1 < @endDate 

這張表有近1000萬條記錄,本次查詢將返回近10000條記錄。

現在,我希望查詢至少使用我的索引IX_TestTable_DateField1索引掃描 + 鍵查找),但它正在執行聚集索引掃描(在 PK 欄位上)。我認為這是因為查詢返回了表的所有欄位。

我之前的想法是:

  1. 如果索引已包含所有欄位,則 SqlServer 將執行 Index Seek;
  2. 如果沒有包含所有欄位,但如果該欄位用於 WHERE 或 ORDER 中,則會使用 Index Scan + Key Lookup;
  3. 如果既不是 1 也不是 2,則進行 Clustered Index Scan;

它是否正確?為什麼沒有發生“索引掃描 + 鍵查找”?

這是微軟所說的優化 SELECT 語句

SQL Server 查詢優化器是一個基於成本的優化器。每個可能的執行計劃在使用的計算資源量方面都有相關的成本。查詢優化器必須分析可能的計劃並選擇估計成本最低的計劃。

$$ … $$ SQL Server 查詢優化器不會只選擇資源成本最低的執行計劃;它選擇以合理的資源成本向使用者返回結果並且返回結果最快的計劃。例如,並行處理查詢通常比串列處理使用更多的資源,但完成查詢的速度更快。

如您所見,查詢優化器將選擇它期望獲得最有效執行的計劃。有時使用 (Index Scan + Key Lookup) 並不是最有效的方法。

作為測試,您可以將您現在獲得的執行計劃STATISTICS TIMESTATISTICS IO結果與為您的查詢生成的結果進行比較,從而強制它使用帶有查詢提示的索引。請注意,我不建議您將此提示用作解決方案,而是作為比較執行性能的一種方式,如果它按照您的意願使用索引。


為了進一步閱讀,Benjamin Nevarez 的文章帶來了一些很好的資訊:SQL Server 查詢優化器

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