SQL Server:根据执行计划忽略索引

时间:2017-05-31 17:59:37

标签: sql-server performance indexing

我有一个运行此语句的存储过程

UPDATE QP.LocalMessage WITH (UPDLOCK, ROWLOCK) 
SET StatusId = 0 
WHERE StatusId = 1 AND DateLockedUntil <= @DateNow

我们已为此更新创建了一个快速运行的索引

CREATE NONCLUSTERED INDEX [IX_LocalMessage_ProcessingLocked] 
    ON [QP].[LocalMessage] ([DateLockedUntil] ASC)
    WHERE ([StatusId] = (1))

但是在查看正在使用的执行计划后,我们没有使用此索引,而是使用聚簇索引扫描。这需要至少在2秒内执行此语句,但我们看到时间达到12-15秒。我想理解为什么它忽略了索引。

2 个答案:

答案 0 :(得分:2)

使用非聚簇索引时,SQL Server需要执行密钥查找操作。在select语句中,可以通过覆盖查询来避免这种情况,在更新语句中,这是无法避免的。

如果谓词返回的记录数很大,那么进行聚簇扫描比使用非聚簇索引查找和键查找更好。

您的查询已参数化,因此SQL Server无法确定将返回的记录数。您可以更新整个表格。

如果某些执行只更新了几条记录并且可以使用非聚集索引查找,那么您可以使用&#34;配置重新编译&#34;来配置您的过程。条款。这将允许SQL Server分析您的过程接收的每个参数值的计划。另一种选择是使用&#34;选项(重新编译)&#34;在你的查询中。

但是,请记住,如果要更新的记录数很少,SQL Server将仅使用非聚簇索引。

你也可以通过使用&#34;(index = yourindexname)&#34;来证明我所说的一切。作为一个查询提示,除了你的表名,并分析统计信息和统计时间,以注意它在查询中使用非聚集索引搜索时有多糟糕,它不应该这样做。

答案 1 :(得分:2)

如果您include (StatusId),那么您的查询可以使用您的过滤索引。

CREATE NONCLUSTERED INDEX [IX_LocalMessage_ProcessingLocked_Include] 
    ON [QP].[LocalMessage] ([DateLockedUntil] ASC)
    include (StatusId)
    WHERE ([StatusId] = (1))

dbfiddle:http://dbfiddle.uk/?rdbms=sqlserver_2016&fiddle=816af692f8993ce8844b5b5c7182f7a1

参考: