4

假设有一个像这样的表:

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)

查询计划显示索引搜索is NULLis not NULL条件,忽略列中 NULL 值的百分比(0% 的 NULL 或 10% 或 90% 或 100%,没关系)。当有两个过滤索引时,查询计划is NULL总是显示索引搜索,可以是索引扫描或表扫描(取决于 NULL 的百分比),但绝不是索引搜索。所以,看起来,本质上的区别在于条件“不是NULL”的处理方式。

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

SqlServer 2008、2008r2 和 2012

4

1 回答 1

2

您看到的查询计划中的 Seek vs Scan 是一个红鲱鱼。

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

通过检查 XML 查询计划,您可以看到索引 Seek 谓词是“#data.Value = Scalar Operator (Null)”,因为每一行都满足该条件,所以这是没有意义的。

于 2013-07-14T04:04:23.167 回答