SQL Server 2008上的间歇性慢查询

Ter*_*ter 5 sql-server performance sql-server-2008

我正在开发一个系统,它定期(每天4-5次)运行一个选择语句,通常需要不到10秒,但定期需要40分钟.

该数据库位于Windows Server 2008 + SQL Server 2008 R2上; 都是64位.

运行数据库的计算机上有一个服务,它轮询数据库并为需要它的记录生成值.然后,使用MFC CRecordset类从使用CFC(VS 2010)编写的第二台计算机上的服务中使用多表连接选择来定期查询这些记录,以提取数据.导致问题的查询示例如下所示.

SELECT DISTINCT "JobKeysFrom"."Key" AS "KeyFrom","KeysFrom"."ID" AS "IDFrom",
"KeysFrom"."X" AS "XFrom","KeysFrom"."Y" AS "YFrom","JobKeysTo"."Key" AS "KeyTo",
"KeysTo"."ID" AS "IDTo","KeysTo"."X" AS "XTo","KeysTo"."Y" AS "YTo",
"Matrix"."TimeInSeconds","Matrix"."DistanceInMetres","Matrix"."Calculated"
FROM "JobKeys" AS "JobKeysFrom"
INNER JOIN "JobKeys" AS "JobKeysTo" ON 
("JobKeysFrom"."Key"<>"JobKeysTo"."Key") AND 
("JobKeysFrom"."JobID"=531) AND 
("JobKeysTo"."JobID"=531)
INNER JOIN "Keys" AS "KeysFrom" ON 
("JobKeysFrom"."Key"="KeysFrom"."Key") AND ("JobKeysFrom"."Status"=4)
INNER JOIN "Keys" AS "KeysTo" ON 
("JobKeysTo"."Key"="KeysTo"."Key") AND ("JobKeysTo"."Status"=4)
INNER JOIN "Matrix" AS "Matrix" ON 
("Matrix"."IDFrom"="KeysFrom"."ID") AND ("Matrix"."IDTo"="KeysTo"."ID")
ORDER BY "JobKeysFrom"."Key","JobKeysTo"."Key"
Run Code Online (Sandbox Code Playgroud)

我尝试了以下内容

  1. 检查索引,所有似乎都正确,它们是活动的,并根据查询使用
  2. 设计顾问回来时没有任何建议
  3. 我试过对索引和数据进行碎片整理
  4. 通过导出数据并在新数据库中重新导入数据,从头开始重建数据库.
  5. 在它上面运行了一个分析器,发现当它出错时,似乎要做数百万(高达1亿)的读取而不是几十万.
  6. 在另一台服务器上运行数据库

在运行查询期间,我可以在管理工作室窗口中运行完全相同的查询,它将在10秒内恢复运行.问题似乎不是锁,死锁,CPU,磁盘或内存相关,因为它在运行数据库的机器只运行这一个查询时已经完成了.服务器有4个处理器和16 GB的内存来运行它.我也尝试将磁盘升级到更快的速度,这没有任何效果.

在我看来,它几乎就像数据库接收查询,开始处理它然后进入休眠40分钟或运行查询而不使用索引.

当需要很长时间时,它最终会完成并将查询结果(通常约70-100000条记录)发送回调用应用程序.

非常感谢任何帮助或建议

Mar*_*ith 3

这听起来很像参数嗅探。

当调用存储过程并且缓存中没有与连接选项匹配的现有执行计划时,set将使用在该调用中传入的参数值来编译新的执行计划。

有时,当传递的参数不典型(例如具有异常高的选择性)时,就会发生这种情况,因此生成的计划将不适合具有不同参数的大多数其他调用。例如,它可能会选择带有索引查找和书签查找的计划,这对于高度选择性的情况来说很好,但如果需要执行数十万次,则效果很差。

这可以解释为什么阅读量会激增。

您的 SSMS 连接可能有不同的SET ...选项,因此当您在 SSMS 内执行存储过程时,不会从缓存中获得相同的有问题的计划

您可以使用以下内容来获取慢速会话的计划

select p.query_plan, *
from sys.dm_exec_requests r
cross apply sys.dm_exec_query_plan(r.plan_handle) p
where r.session_id = <session_id>
Run Code Online (Sandbox Code Playgroud)

然后与好会话的计划进行比较。

如果您确定参数嗅探有问题,您可以使用OPTIMIZE FOR提示来避免它选择错误的计划。