2011-05-12 149 views
3

表定義:爲什麼這個查詢不使用正確的索引?

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 

enter image description here

這個代碼不使用我的IX_ExceptionDate(從執行計劃收集)。它對主鍵索引進行了集羣掃描。但是,下面的代碼並使用IX_ExceptionDate指數:

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

enter image description here

這是爲什麼?

編輯:添加視覺執行計劃。

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

查詢1:

| --Table插入(OBJECT:([#YST]),SET:([#YST] [ID] = [Expr1006],[#YST] [ DomainLogin] = [MarketStats]。[dbo]。[AllErrors]。[DomainLogin],[#yst]。[ExceptionDate] = [MarketStats]。[dbo]。[AllErrors]。[ExceptionDate],[#yst]。[例外情況] = [MarketStats]。[dbo]。[AllErrors]。[ExceptionDescr],[#yst]。[MarketName] = [MarketStats]。[dbo]。[AllErrors]。[MarketName],[#yst]版本] = [MarketStats]。[dbo]。[AllErrors]。[Version])) | --Top(ROWCOUNT est 0) | --Compute Scalar(DEFINE:([Expr1006] = setidentity([MarketStats]。 ([市場統計])。 [所有錯誤]。[PK_AllErrors]),地點:([MarketStats]。[dbo]。[AllErrors]。[ExceptionDate]> = [@昨天]和[MarketStats]。[dbo]。[AllErrors]。 [ExceptionDate] < = [@昨天] + '1900年1月2日00:00:00.000'))

問題2:

| --Table插入(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]。 [市場名稱] = [MarketStats]。[dbo]。[AllErrors]。[MarketName],[#yst]。[Version] = [MarketStats]。[dbo]。[AllErrors]。[Version ])) | --Top(ROWCOUNT est 0) | --Compute Scalar(DEFINE:([Expr1006] = setidentity([MarketStats]。[dbo]。[AllErrors]。[ID],( - 7), (外部參考:([MarketStats]。[dbo]。[AllErrors]。[ID],[Expr1008])使用無預置)([市場策略]。[市場策略]。[市場策略]。[所有錯誤]。[IX_ExceptionDate]),SEEK :(市場策略]。[dbo]。[AllErrors]。[ExceptionDate]> = [@昨天]和[MarketStats]。[dbo]。[AllErrors]。[ExceptionDate] < = [@yesterday] +'1900-01-02 00:00:00.000'),地點:([MarketStats]。[dbo]。 [AllErrors]。[ExceptionDate] = [MarketStats]。[dbo]。[AllErrors]。[ExceptionDate])ORDERED FORWARD) | - 羣集索引尋找(OBJECT :(市場策略]。[dbo]。[AllErrors]。 [PK_AllErrors]),SEEK:([MarketStats]。[dbo]。[AllErrors]。[ID] = [MarketStats]。[dbo]。[AllErrors]。[查看]查看訂單前進)

+0

你可以發佈執行計劃嗎? – Lamak 2011-05-12 17:30:53

+0

你可以發佈這個計劃,我對'| - 集羣索引掃描(OBJECT:([aspnetdb]。[dbo]。[AllErrors]。[PK_AllErrors]),WHERE:([aspnetdb]。[ dbo]。[AllErrors]。[ExceptionDate]> = [@昨天] AND [aspnetdb]。[dbo]。[AllErrors]。[ExceptionDate] <= [@ yesterday] +'1900-01-02 00:00:00.000 '))' – SQLMenace 2011-05-12 17:31:59

+0

'| - 集羣索引掃描(OBJECT:([aspnetdb]。[dbo]。[AllErrors]。[PK_AllErrors]),WHERE:([aspnetdb]。[dbo]。[AllErrors]。[ExceptionDate ]> = [@昨天] AND [aspnetdb]。[dbo]。[AllErrors]。[ExceptionDate] <= [@ yesterday] +'1900-01-02 00:00:00.000'AND [aspnetdb]。[dbo] 。[AllErrors]。[ExceptionDate] = [aspnetdb]。[dbo]。[AllErrors]。[ExceptionDate]))' – SQLMenace 2011-05-12 17:32:17

回答

6

它不知道所產生的變量的值將是什麼時,它編譯查詢。你可以試試OPTION (RECOMPILE)

我認爲在查詢中增加AND子句(即使邏輯上它使得它不再有選擇性)必須誤導優化器以更高的選擇性估計查詢,從而爲您提供您想要的計劃!

您在沒有ExceptionDate = ExceptionDate版本估計88234.8行與8823.48

一般在沒有可用的統計數據的SQL Server版本的評論說回落到依賴於的類型比較操作符的啓發謂詞。

它假設一個>謂詞將返回行的30%,例如一個=謂詞將返回10%的行,因此它看起來就是將它直接應用於第一個估計的結果。有趣的是,它沒有考慮到這樣一個事實,即平等與這裏的專欄本身相反!

c.f. Best Practices for Managing Statistics - Avoid use of local variables in queries

5

簡短的回答:由於「SELECT *」,您的查詢命中聚集索引:密鑰查找操作比聚集索引掃描成本更高。

看到不同的查詢計劃從

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 
+0

如果您需要表中的所有數據。一旦你得到了相當數量的行,無論如何,所有的成本應該在插入。 – SRoderick 2011-05-12 18:24:59

+0

這是一個很好的想法,但結果是相同的(我確實需要表中的所有列,而不僅僅是ExceptionDate)。使用*是不好的做法,恕我直言, – AngryHacker 2011-05-12 18:30:12

+1

。更好地列舉明確的字段 – 2011-05-13 08:40:12

相關問題