为什么覆盖过滤索引进行查找

Why a coverage filtered index do a Lookup

我有一个 table 需要每分钟检查一次,以便在总数大于某个数字时发出警报。

 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

但是看执行计划,有一个key lookup

我不明白为什么,因为索引有两列用于查询。

谁能解释一下为什么?

如果条件为 NULL,那么记录集将只有一个值,为什么需要该值的索引?它会根据什么进行排序?因此,您需要在 processedAt 不为 null 的情况下执行过滤索引,并在代码中使用该条件将有所帮助

您需要在创建索引脚本的 INCLUDED 列中包含 ProcessedAt 列

添加示例来解释@Martin Smith 的评论:

Table 脚本:

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
)

插入 table 条记录:

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

在 id_for_FilteredIndex 列上创建非聚集过滤索引,条件在不同的列上 another_id

create nonclustered index NCI_TestKeyLookup on dbo.TestKeyLookup(id_for_filteredIndex)
where another_id > **673105**

如果我使用完全相同的条件查询 table,则优化器未使用 KeyLookup

select  count(id_for_filteredIndex) from TestKeyLookup with(index(NCI_TestKeyLookup))
where another_id > 673105

如果我通过增加 +5 或 10 来更改条件,那么它会对聚集索引执行 keyLookup

select  count(id_for_filteredIndex) from TestKeyLookup with(index(NCI_TestKeyLookup))
where another_id > 673110

我只是想解释一下。如果条件发生变化,它会使用 KeyLookup 来获取。在某种程度上,如果该列可以为空并且它具有空值那么它是不同的