【问题标题】:SQL "find missing index" script suggests missing index that already exists? Query in top 10 CPU listSQL“查找缺失的索引”脚本提示缺失的索引已经存在?查询前 10 CPU 列表
【发布时间】:2014-08-12 13:27:15
【问题描述】:

一个查询位于 CPU 密集度最高的列表的顶部,但它的简单性(参见下面的示例)与此相矛盾。然而,“查找缺失的索引”脚本建议为表创建一个索引......但这个确切的(列顺序和包含)索引已经存在。

SELECT COUNT(Id) 
  FROM dbo.ProductOrder
 WHERE userId = @userId
   AND status = @status

“查找缺失的索引”脚本建议在 userId 和状态上建立索引。

我们在几周前注意到缺少的索引提示,并发现了一篇帖子(某处)这将是 SQL Server R2 SP1(我们使用的版本)中的一个错误。

但现在查询是(并保持)在前 10 名中...我不确定了。

我们尝试过的事情:

  • 将 ID 添加到包含列表(不建议)
  • NOLOCK / READ UNCOMMITED 事务隔离级别
  • sp_recompile 在桌子上

我们有一个紧凑的维护计划,以确保将碎片控制在最低限度。

这里会发生什么?

编辑:我在开始发帖时提到了执行计划,但执行计划实际上并没有提到索引(不再)。 “查找缺失的索引”脚本可以。

编辑 2:索引定义

CREATE NONCLUSTERED INDEX [ProductOrder_UserStatus_Nidx] ON [dbo].[ProductOrder]
(
    [userId] ASC,
    [status] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO

编辑 3:缺少索引输出

statement: dbo.ProductOrder
improvement_measure: 187243,941382055
create_index_statement: CREATE INDEX [missing_index_4_3_ProductOrder] ON [dbo].[ProductOrder] ([userId], [status])
group_handle: 4
unique_compiles: 10
user_seeks: 51161
user_scans: 0
last_user_seek: 2014-06-22 10:06:12.390
last_user_scan: NULL
avg_total_user_cost: 8,77252167199463
avg_user_impact: 41,72
system_seeks: 0
system_scans: 0
last_system_seek: NULL
last_system_scan: NULL
avg_total_system_cost: 0
avg_system_impact: 0
database_id: 8
object_id: 2014122416

更新:找到正确查询的新脚本

我们正在查看错误的查询。一个新脚本在查询计划中找到了实际生成缺失索引语句的脚本:

CREATE PROCEDURE [dbo].[ProductOrder_GetByUserAndStatus]
  @userId INT, 
  @status INT,
  @deliveryStatus INT
AS

 SELECT U.id
      , U.email
      , U.[language]
      , U.username
      , U.firstname + ' ' + ISNULL(u.middlename, '') + ' ' + u.lastname AS fullname
      , pp.[product]
      , pp.[status]
      , pp.[deliveryStatus]
   FROM [dbo].[ProductOrder] PO
   JOIN [dbo].[User] U ON U.[id] = PO.[userId] 
    AND PO.[pool] = @userId 
      AND PO.[status] = @status
    AND PO.[deliveryStatus] = ISNULL(@deliveryStatus, PO.[deliveryStatus])

RETURN 0

可能是因为 where 子句中的最后一行实现了可选的过滤器参数而导致 SQL 服务器丢失?

我已尝试创建更新索引以在列列表中包含 deliveryStatus 以及 INCLUDE 语句(在两个单独的更新中,运行统计信息和重新编译);第一个解决方案性能下降(缺少的索引仍在计划中),而第二个解决方案没有差异。

将此问题作为 SQL Server 中的错误关闭?

【问题讨论】:

  • 它发生了......有时它建议重复索引。这就是为什么你不应该盲目地听从它的建议......你的统计数据是最新的吗?
  • 如果你 100% 确定索引是好的,你可以使用索引提示来强制 SQL Server 使用那个索引。
  • 使用强制索引提示作为绝对的最后手段。
  • 那么执行计划是什么样的呢?它不是在寻找这两列的索引吗?
  • 另外,目前的执行计划到底有什么问题?仅仅因为它在“前 10 名”中并不意味着这是一个糟糕的计划。您可以简单地每小时调用一百万次。

标签: sql sql-server performance indexing sql-execution-plan


【解决方案1】:

那么,有哪些索引?希望有一个userId, status INCLUDE (Id)。不需要其他任何东西(任何额外的列都会减慢这个查询的速度)。如果 Id 不是 null 或 CI 的一部分,您甚至不需要包含它。也许,你的意思是并且应该写COUNT(*),因为你可能不在乎不计算Id中的空值。

如果您想通过聚集索引将其优化为单行查找(速度非常快),请使用按userId, status 分组的索引视图。

与普遍的迷信相反,锁定在这里不太可能成为嫌疑人。其实NOLOCK很危险。

【讨论】:

  • Id 的包含不存在。我们尝试添加 Id,但丢失的索引一直显示(没有 Id 或任何包含)。我将计数更改为 *.我还将查看索引视图作为解决方案。
  • 缺少索引消息只是一个错误。或不。如果您发布索引定义,我们可以确定。如果要计算的行数很多,或者查询运行非常频繁,那么简单的索引就无能为力了。
  • 我已经添加了索引def。表中有 780K 行。
猜你喜欢
  • 2018-02-07
  • 1970-01-01
  • 1970-01-01
  • 2010-11-06
  • 1970-01-01
  • 1970-01-01
  • 2019-03-07
  • 1970-01-01
  • 2021-12-26
相关资源
最近更新 更多