簡體   English   中英

為什么這個查詢不使用正確的索引?

[英]Why doesn't this query use the proper index?

表定義:

CREATE TABLE [dbo].[AllErrors](
  [ID] [int] IDENTITY(1,1) NOT NULL,
  [DomainLogin] [nvarchar](50) NULL,
  [ExceptionDate] [datetime] NULL,
  [ExceptionDescr] [nvarchar](max) NULL,
  [MarketName] [nvarchar](50) NULL,
  [Version] [nvarchar](50) NULL,
  CONSTRAINT [PK_AllErrors] PRIMARY KEY CLUSTERED ([ID] ASC)
)

-- Add an index on the date
CREATE NONCLUSTERED INDEX [IX_ExceptionDate] ON [dbo].[AllErrors] ([ExceptionDate] ASC)

我運行這個查詢:

declare @yesterday datetime
select @yesterday = getdate() - 1

SELECT * INTO #yst
from AllErrors 
where ExceptionDate between @yesterday and @yesterday + 1

在此輸入圖像描述

此代碼不使用我的IX_ExceptionDate (從執行計划中收集)。 它對主鍵索引執行群集掃描。 但是,下面的代碼確實使用了IX_ExceptionDate索引:

SELECT * INTO #yst
from AllErrors 
where ExceptionDate between @yesterday and @yesterday + 1
  AND ExceptionDate = ExceptionDate

在此輸入圖像描述

為什么是這樣?

編輯:添加了視覺執行計划。

編輯:下面的文本執行計划。

查詢1:

| - 表格插入(OBJECT:([#yst]),SET :( [#yst]。[ID] = [Expr1006],[#yst]。[DomainLogin] = [MarketStats]。[dbo]。[AllErrors ]。[DomainLogin],[#yst]。[ExceptionDate] = [MarketStats]。[dbo]。[AllErrors]。[ExceptionDate],[#yst]。[ExceptionDescr] = [MarketStats]。[dbo]。[AllErrors ]。[ExceptionDescr],[#yst]。[MarketName] = [MarketStats]。[dbo]。[AllErrors]。[MarketName],[#yst]。[Version] = [MarketStats]。[dbo]。[AllErrors ]。[Version]))| - Top(ROWCOUNT est 0)| - 計算標量(DEFINE :( [Expr1006] = setidentity([MarketStats]。[dbo]。[AllErrors]。[ID],( - 7 ),(0),N'#yst')))| - 聚集索引掃描(OBJECT:([MarketStats]。[dbo]。[AllErrors]。[PK_AllErrors]),WHERE:([MarketStats]。[dbo] ]。[AllErrors]。[ExceptionDate]> = [@昨天] AND [MarketStats]。[dbo]。[AllErrors]。[ExceptionDate] <= [@ yesterday] +'1900-01-02 00:00:00.000' ))

查詢2:

| - 表格插入(OBJECT:([#yst]),SET :( [#yst]。[ID] = [Expr1006],[#yst]。[DomainLogin] = [MarketStats]。[dbo]。[AllErrors ]。[DomainLogin],[#yst]。[ExceptionDate] = [MarketStats]。[dbo]。[AllErrors]。[ExceptionDate],[#yst]。[ExceptionDescr] = [MarketStats]。[dbo]。[AllErrors ]。[ExceptionDescr],[#yst]。[MarketName] = [MarketStats]。[dbo]。[AllErrors]。[MarketName],[#yst]。[Version] = [MarketStats]。[dbo]。[AllErrors ]。[Version]))| - Top(ROWCOUNT est 0)| - 計算標量(DEFINE :( [Expr1006] = setidentity([MarketStats]。[dbo]。[AllErrors]。[ID],( - 7 ),(0),N'#yst')))| - 嵌套循環(內部連接,外部參考:([MarketStats]。[dbo]。[AllErrors]。[ID],[Expr1008])優化為UNORDERED PREFETCH)| - 索引查詢(OBJECT:([MarketStats]。[dbo]。[AllErrors]。[IX_ExceptionDate]),SEEK:([MarketStats]。[dbo]。[AllErrors]。[ExceptionDate]> = [@昨天]和[MarketStats]。[dbo]。[AllErrors]。[ExceptionDate] <= [@yesterday] +'1900-01-02 00:00:00.000'),其中:([MarketStats]。[dbo]。 [AllErrors]。[ExceptionDate] = [MarketStats]。[DBO]。[AllErrors]。[E xceptionDate])ORDERED FORWARD)| - 集群索引查詢(OBJECT:([MarketStats]。[dbo]。[AllErrors]。[PK_AllErrors]),SEEK:([MarketStats]。[dbo]。[AllErrors]。[ID ] = [MarketStats]。[dbo]。[AllErrors]。[ID])LOOKUP ORDERED FORWARD)

在編譯查詢時,它不知道變量的值是什么。 你可以試試OPTION (RECOMPILE)

我認為在查詢中添加AND子句(即使在邏輯上它使它不再具有選擇性)必須誤導優化器以更高的選擇性估計查詢,從而為您提供所需的計划!

您在評論中說沒有ExceptionDate = ExceptionDate的版本估計為88234.8行,版本為8823.48

通常,在沒有可用統計信息的情況下,SQL Server會根據謂詞中比較運算符的類型回退到啟發式算法。

它假定>謂詞將返回30%的行,例如,a =謂詞將返回10%的行,因此看起來它只是直接將其應用於第一次估計的結果。 有趣的是,它沒有考慮到這里的等於對立柱本身的事實!

cf 管理統計信息的最佳實踐 - 避免在查詢中使用局部變量

簡短回答:由於“SELECT *”,您的查詢會遇到聚簇索引:Key Lookup操作比聚簇索引掃描要昂貴得多。

查看由此產生的不同查詢計划

declare @yesterday datetime
select @yesterday = getdate() - 1

SELECT * INTO dbo.#yst
from AllErrors WITH (INDEX = IX_ExceptionDate)
where ExceptionDate between @yesterday and @yesterday + 1

declare @yesterday datetime
select @yesterday = getdate() - 1

SELECT * INTO dbo.#yst
from AllErrors
where ExceptionDate between @yesterday and @yesterday + 1

declare @yesterday datetime
select @yesterday = getdate() - 1

SELECT ExceptionDate INTO dbo.#yst
from AllErrors
where ExceptionDate between @yesterday and @yesterday + 1

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM