sql-server – 过滤索引寻找`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

要么

select ID from #data where Value is not NULL

如果我检查查询计划,我会看到在第一种情况下执行索引查找,在第二种情况下执行索引扫描.为什么它在第一种情况下寻找并在第二种情况下扫描?

评论后补充:

如果我创建普通覆盖索引而不是两个过滤覆盖:

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

查询计划显示索引查找为NULL且不是NULL条件,忽略列中NULL值的百分比(0%的NULL或10%或90%或100%,无关紧要).
当有两个过滤索引时,查询计划显示索引查找始终为NULL,并且可以是索引扫描或表扫描(取决于NULL的%),但它绝不是索引查找.所以,似乎,差别在于条件’不是NULL’的处理方式.

这可能意味着,如果索引仅用于’is not NULL’检查,那么普通索引或过滤索引应该表现得更好并且是首选,不是吗?哪一个?

SqlServer 2008,2008r2和2012

最佳答案 您正在查看的查询计划中的Seek vs Scan是一个红鲱鱼.

在这两种情况下,通过从头到尾扫描适当的非聚集索引来回答查询,返回每一行.

通过检查XML查询计划,您可以看到索引Seek谓词是“#data.Value = Scalar Operator(Null)”,这在每行符合该条件时毫无意义.

点赞