我正在开发一个系统,它定期(每天4-5次)运行一个select语句,通常需要不到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"
我试过以下
在运行查询期间,我可以在管理工作室窗口中运行完全相同的查询,它将在10秒内恢复运行。问题似乎不是锁,死锁,CPU,磁盘或内存相关,因为它在运行数据库的机器只运行这一个查询时已经完成了。服务器有4个处理器和16 GB的内存来运行它。我也尝试将磁盘升级到更快的磁盘,这没有任何效果。
在我看来,它几乎就像数据库收到查询,开始处理它然后进入休眠状态40分钟或运行查询而不使用索引。
当需要很长时间时,它最终会完成并将查询结果(通常约70-100000条记录)发送回调用应用程序。
非常感谢任何帮助或建议,非常感谢
答案 0 :(得分: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>
然后与良好会话的计划进行比较。
如果确定参数嗅探有问题,可以使用OPTIMIZE FOR提示来避免选择错误的计划。
答案 1 :(得分:0)
检查您是否正在运行正在重建索引的维护任务,或者在执行查询时数据库统计信息无效。
如果查询没有使用您的索引,这就是人们期望看到的东西,这通常是因为查询在运行时无法访问索引,或者因为统计信息无效并且生成优化器认为您的大型表中只有几行,并且使用全表扫描比使用索引访问的查询运行速度更快。