Отфильтрованный индекс ищет условие `is NULL` и сканирует противоположное

Предположим, что есть таблица вида:

create table #data (ID int identity(1, 1) not NULL, Value int)

Поместите в него некоторые данные:

insert into #data (Value)
select top (1000000) case when (row_number() over (order by @@spid)) % 5 in (0, 1) then 1 else NULL end
from sys.all_columns c1, sys.all_columns c2

И два индекса:

create index #ix_data_n on #data (Value) include (ID) where Value is NULL
create index #ix_data_nn on #data (Value) include (ID) where Value is not NULL

Данные запрашиваются так:

select ID from #data where Value is NULL

or

select ID from #data where Value is not NULL

Если я просматриваю план запроса, я вижу, что в первом случае выполняется поиск по индексу, а во втором случае выполняется сканирование индекса. Почему он ищет в первом случае и сканирует во втором?

Дополнение после комментариев:

Если я создам обычный индекс покрытия вместо двух отфильтрованных покрытий:

create index #ix_data on #data (Value) include (ID)

План запроса показывает поиск по индексу для условий is NULL и is not NULL без учета % значений NULL в столбце (0% значений NULL или 10%, или 90%, или 100%, не имеет значения). Когда есть два отфильтрованных индекса, план запроса всегда показывает поиск индекса для is NULL и может быть сканированием индекса или сканированием таблицы (в зависимости от % NULL), но это никогда не поиск индекса. Таким образом, кажется, что по существу разница заключается в том, как обрабатывается условие «не NULL».

Это означает, наверное, что если индекс предназначен только для проверки "не является NULL", то либо обычный индекс, либо фильтрованный индекс должны работать лучше и быть предпочтительнее, не так ли? Который из?

SQLServer 2008, 2008r2 и 2012


person i-one    schedule 11.07.2013    source источник
comment
посмотрите ответ на этот вопрос: заголовок stackoverflow.com/questions/3829929/   -  person Avitus    schedule 11.07.2013
comment
Поскольку условие NOT NULL достигает критической точки, когда на самом деле более эффективно использовать сканирование (в вашем случае это должно быть примерно 60% таблицы).   -  person Aaron Bertrand    schedule 11.07.2013
comment
Если индекс используется только для запроса данных, удовлетворяющих is not NULL условию, какой тип индекса лучше, обычный или фильтрованный?   -  person i-one    schedule 12.07.2013


Ответы (1)


Seek vs Scan в планах запросов, которые вы видите, является отвлекающим маневром.

В обоих случаях ответом на запрос является сканирование соответствующего некластеризованного индекса от начала до конца с возвратом каждой строки.

Изучив план XML-запроса, вы можете увидеть, что предикат индекса Seek — это «#data.Value = Scalar Operator (Null)», что бессмысленно, поскольку каждая строка соответствует этому критерию.

person StrayCatDBA    schedule 14.07.2013