SQL"找到缺失的索引"脚本建议缺少已存在的索引?查询前10个CPU列表

时间:2014-06-22 09:57:05

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

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

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

“查找缺失索引”脚本建议使用userId和status的索引。

我们注意到几周前丢失的索引建议发现一个帖子(某处),这可能是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服务器中的错误关闭?

1 个答案:

答案 0 :(得分:3)

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

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

与常见的迷信相反,锁定在这里不是一个可能的嫌疑人。事实上,NOLOCK非常危险。