2016-09-21 36 views
2

我有一張表,當總數大於一個數字時,需要檢查每分鐘提醒。爲什麼覆蓋範圍篩選索引執行查找

SELECT 
    count(CreatedAt) Total 
FROM 
    Process d 
WHERE 
    d.ProcessedAt is null 
    AND DATEDIFF(second, GETUTCDATE(), d.CreatedAt) > 30 

我的想法是創建一個過濾索引,是這樣的:

CREATE NONCLUSTERED INDEX [FIX_Process_CreatedAt_ProcessedAt] ON [dbo].[Process] 
(
    [CreatedAt] ASC 
) 
WHERE ProcessedAt IS NULL 

但看執行計劃,有一個鍵查找。

我不明白爲什麼,因爲索引有兩列用於查詢。

任何人都可以解釋我爲什麼嗎?

+1

你的感覺是正確的。這是沒有道理的,不應該邏輯上要求。但這是一個從未被修復的優化器限制。你可以在這裏投票https://connect.microsoft.com/SQLServer/feedback/details/454744/filtered-index-not-used-and-key-lookup-with-no-output –

+0

@MartinSmith但是這裏的情況是因爲ProcessedAt與索引的CreatedAt列不同,爲了實現該條件'd.ProccessedAt爲null',它必須使用該值。對於該優化器必須執行鍵查找才能獲得適當的值。你提到的錯誤只有當索引列和謂詞列是相同的。我還沒有檢查行爲雖然.. –

+0

不,你已經錯過了這一點。它在邏輯上不*具有*進行鍵查找來獲得該列。它正在檢查的條件已由過濾的索引條件保證。條件對索引中的所有行都成立。它在邏輯上可以簡單地跳過檢查它作爲OP懷疑。查找的唯一原因是因爲優化器當前不包含該邏輯,但它可以並且應該被添加。 –

回答

1

如果條件爲NULL,那麼您將只有一個值的記錄集,爲什麼你需要一個索引到該值?在什麼基礎上它會做排序?所以,你需要做的過濾索引,其中,processedAt不爲空並使用代碼條件將有助於

您需要包括ProcessedAt列在創建索引腳本

包列增加一個例子解釋@馬丁史密斯評論:

表腳本:

Create Table TestKeyLookup 
(
id int identity(1,1) primary key -- Created PK which will create clustered Index 
,id_for_filteredIndex int NOT NULL 
,another_id int NOT NULL 
) 

插入到表中的記錄:

declare @i int = 50 
while @i < 1000000 
begin 
    insert into TestKeyLookup (id_for_filteredIndex, another_id) values (@i, @i+5) 
    set @i = @i + 10 
END 

與不同的列條件創建於id_for_FilteredIndex列非聚集過濾指數another_id

create nonclustered index NCI_TestKeyLookup on dbo.TestKeyLookup(id_for_filteredIndex) 
where another_id > **673105** 

如果我查詢表完全相同的條件,那麼優化器不使用KeyLookup

select count(id_for_filteredIndex) from TestKeyLookup with(index(NCI_TestKeyLookup)) 
where another_id > 673105 

It does use filtered index

如果我通過增加甚至+5或10來改變條件,那麼它確實keyLookup到聚集索引

select count(id_for_filteredIndex) from TestKeyLookup with(index(NCI_TestKeyLookup)) 
where another_id > 673110 

Different Id where another_id is greater than filtered index condition

我試圖解釋這只是..如果在條件的變化,然後它使用KeyLookup獲取。從某種意義上說,如果列是可以空的,並且它是空值,那麼它是不同的

+0

在Process表中,它可能有很多行,ProcessedAt = NULL,每一行都有一個不同的CreatedAt。這個索引的目的只是用在這個查詢中,並且速度很快,因爲只需要檢查ProcessedAt中的那些爲null,我認爲過濾索引可能是一個好的解決方案。 –

+0

得到你,現在只檢查你的索引列是'CreatedAt'。鍵查找是因爲對於選定的createdAt值,它必須檢查ProcessedAt列是否爲空,因此它會進行鍵查找,如果包含ProcessedAt在'包含列'中,您將獲得索引掃描本身 –

+0

我認爲添加過濾器,引擎會意識到並且不需要該列。謝謝!!! –