【问题标题】:SQL Server : index ignored based on Execution PlanSQL Server:根据执行计划忽略索引
【发布时间】:2017-05-31 17:59:36
【问题描述】:

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

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 秒的时间。我想了解它为什么忽略索引。

【问题讨论】:

  • 我能想到两个原因。 1. 存储过程已经编译并存储了计划(您可以测试 WITH RECOMPILE)和 2. SQL Server 发现使用该索引将花费与使用 PK 相同的时间。也许您可以尝试在该索引中包含您需要的字段
  • 问题:1)什么版本的SQL Server,? 2) 执行计划估计它将更新多少行? 3) 表中有多少行?

标签: sql-server performance indexing


【解决方案1】:

使用非聚集索引时,SQL Server 需要进行键查找操作。在 select 语句中,这可以通过覆盖查询来避免,在 update 语句中,这是无法避免的。

如果谓词返回的记录数很大,则最好进行聚集扫描而不是非聚集索引查找和键查找。

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

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

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

您还可以通过使用“(index=yourindexname)”作为除表名之外的查询提示来证明我所说的一切,并分析统计信息 io 和统计时间以注意使用非聚集索引查找时的情况有多糟糕在查询中它不应该这样做。

【讨论】:

  • 我相信你我已经更改了查询,现在它正在使用索引。即使在我们的开发环境中,当状态一有 0 条记录时,它也需要 1 分钟才能运行。现在不到 1 秒: UPDATE LME WITH (UPDLOCK, ROWLOCK) SET StatusId = 0 FROM QP.LocalMessage AS LME WITH (UPDLOCK, ROWLOCK) INNER JOIN (SELECT Id FROM QP.LocalMessage WHERE StatusId = 1 ) as ONE ON ONE.Id = LME.Id WHERE StatusId = 1 AND DateLockedUntil
【解决方案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


参考:

【讨论】:

  • 感谢您的参考,我认为它会知道使用索引,因为它也被相同的 statusId 过滤。这是一本很好的书。我以前也从未听说过 dbfiddle。看起来很神奇!谁创造了这个?我还添加了使用内部连接所做的更改。似乎它仍然比在索引中使用包含的包含更快。唯一可能的问题是“表假脱机”,如果有很多记录可能会影响性能dbfiddle.uk/…
  • @greektreat Jack Douglas 制作了 dbfiddle.uk A new fiddle for dba.se
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-30
相关资源
最近更新 更多