假设有一个表格如下:
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)”,这在每行符合该条件时毫无意义.