【问题标题】:Intermittent slow query on SQL Server 2008SQL Server 2008 上的间歇性慢查询
【发布时间】:2010-08-25 12:59:23
【问题描述】:

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

数据库在 Windows Server 2008 + SQL Server 2008 R2 上;都是64位的。

在运行数据库的机器上有一个服务轮询数据库并为需要它的记录生成值。然后,使用 MFC CRecordset 类从用 C++(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"

我已经尝试了以下

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

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

在我看来,就好像数据库接收到查询,开始处理它,然后进入休眠状态 40 分钟或在不使用索引的情况下运行查询。

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

任何帮助或建议将不胜感激,非常感谢

【问题讨论】:

  • 此查询是否作为参数化存储过程运行?
  • 你能避免SELECT DISTINCT吗?这会严重影响性能。
  • @Yves:听起来它的性能足以运行 adhoc,并在 10 秒内返回。
  • 你能用 TOP 100 试试,看看在服务中执行速度是否更快?
  • 谁可以更改状态字段 (Status=4)???

标签: sql-server sql-server-2008 performance


【解决方案1】:

这听起来很像参数嗅探。

当调用存储过程并且缓存中没有与连接的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 提示来避免它选择错误的计划。

【讨论】:

  • 我认为我们的论述建立在无效的初始条件和陈述上:)
【解决方案2】:

检查您没有正在运行的维护任务正在重建索引,或者您的数据库统计信息在执行查询时以某种方式无效。

如果查询没有使用您的索引,这正是人们期望看到的事情,这通常是因为查询在运行时无法访问索引,或者因为统计信息无效并导致优化器认为您的大表中只有几行,并且使用全表扫描查询会比使用索引访问运行得更快。

【讨论】:

  • 您错过了同一查询的并发执行快速返回这一点?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多