2016-09-21 5 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 в ВКЛЮЧЕННОГО колонка в сценарии создания индекса

Добавление примера для объяснения @Martin Смита комментарий:

Таблица сценария:

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 

Создание Non кластерного отфильтрованный индекса на столбце 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 для извлечения. В некотором смысле вы правы, если столбец имеет значение NULL, и он имеет нулевые значения, тогда он отличается

+0

В таблице Process это может иметь много строк с ProcessedAt = NULL, каждый с другой CreatedAt. Цель этого индекса должна использоваться только в этом запросе и быть быстрым, так как только нужно проверить, что для тех, у кого ProcessedAt является null, я предположил, что отфильтрованный индекс может быть хорошим решением. –

+0

Попал на вас, теперь только проверяя, что ваш индексный столбец «CreatedAt». Поиск ключа происходит потому, что для выбранного значения createdAt он должен проверять столбец ProcessedAt, является ли он нулевым или нет, поэтому он выполняет ключевой поиск, если вы включили ProcessedAt в «Включить столбец» вы попадете в сканирование индекса –

+0

Я думал, что добавление фильтра, движок понял бы и не нуждался бы в столбце. Благодаря!!! –