MS SQL Server 2005 - 存储过程“自发中断”

时间:2009-06-18 21:19:56

标签: sql sql-server sql-server-2005 tsql stored-procedures

客户端在执行存储过程时报告了非常奇怪行为的重复实例。

它们具有运行易失性数据集的缓存转置的代码。如果出现以下情况,则编写存储过程以按需重新处理数据集:
1.自上次重新处理以来,数据集发生了变化 2.数据集已保持5分钟不变

(第二个条件在更改期间停止大量重复重新计算。)


这个工作正常几个星期,SP花了1-2秒完成重新处理,它只在需要时才这样做。然后......

  • SP突然“停止工作”(它只是继续运行而且从未返回)
  • 我们以微妙的方式更改了SP,然后又恢复了工作
  • 几天后它再次停止工作
  • 然后有人说“我们以前见过这个,只是重新编译SP”
  • 在没有更改代码的情况下,我们重新编译了SP,并且它正常工作
  • 几天后它再次停止工作


现在已经重复了很多次。 SP突然“停止工作”,永不返回,客户端超时。 (我们尝试通过管理工作室运行它,并在15分钟后取消查询。)

然而,每次我们重新编译SP时,它都会突然再次发挥作用。

我还没有在适当的EXEC声明中尝试过WITH RECOMPILE,但我并不特别想这样做。它每小时被调用一百次,通常什么都不做(它只能每天重新处理数据几次)。如果可能的话,我想避免重新编译什么是相对复杂的SP的开销“只是为了避免”不应该“发生的事情......


  • 以前有没有人经历过这个?
  • 有没有人对如何克服它有任何建议?


干杯,
DEMS。


修改

pseduo代码如下:

  • 从table_x
  • 中读取“a”
  • 从table_x
  • 中读取“b”
  • 如果(a< b)返回
  • BEGIN TRANSACTION
  • DELETE table_y
  • INSERT INTO table_y< 3选择联合在一起>
  • UPDATE table_x
  • COMMIT TRANSACTION

选择“不漂亮”,但是当在线执行时,它们会立即执行。包括SP何时拒绝完成。分析器显示它是SP“停止”

的INSERT

SP没有参数,sp_lock没有显示任何阻塞进程的内容。

8 个答案:

答案 0 :(得分:3)

这是参数嗅探的足迹。是的,第一步是尝试使用RECOMPILE,尽管它并不总是按照你想要的方式在2005年工作。

更新: 我会尝试在INSERT上进行语句级重新编译,因为这可能是一个统计问题(哦,是的,检查自动化统计更新是否已启用)。

如果这似乎不适合参数嗅探,那么比较实际查询计划从正确运行时和从何时运行它(如果你不能得到实际的估计计划,虽然实际更好)。您正在查看计划是否发生变化。

答案 1 :(得分:3)

我完全同意参数嗅探诊断。如果你有SP的输入参数变化(或者即使它们没有变化) - 一定要用局部变量掩盖它们并使用SP中的局部变量。

如果设置正在更改,您也可以使用WITH RECOMPILE,但查询计划不再有任何好处。

在SQL Server 2008中,您可以使用OPTIMIZE FOR UNKNOWN功能。

此外,如果您的流程涉及填充表格然后在另一个操作中使用该表格,我建议您将该流程分解为单独的SP并单独调用它们WITH RECOMPILE。我认为当你填充一个表然后使用该表的结果来执行操作时,在该过程开始时生成的计划有时可能非常差(很难完成)。因为在初始计划时,表格与初始插入后的表格有很大不同。

答案 2 :(得分:1)

正如其他人所说,有关数据或源表统计信息更改方式的一些原因导致缓存的查询计划失效。

WITH RECOMPILE可能是最快的修复方法 - 使用SET STATISTICS TIME ON找出重新编译成本实际上是什么,然后再将其解除。

如果这仍然不是一个可接受的解决方案,那么最好的选择可能是尝试重构insert语句。

您没有说明您是否在插入语句中使用UNIONUNION ALL。我看到INSERT INTO UNION生成了一些奇怪的查询计划,尤其是在SP2之前的SQL 2005版本上。

  • Raj建议放弃和 用。重新创建目标表 SELECT INTO是一种方法。

  • 你也可以尝试选择每个 三个源查询到自己的 临时表,然后UNION那些临时表 一起插入。

  • 或者,你可以尝试一下 这些建议的组合 - 将联盟的结果放入 临时表SELECT INTO, 然后从那里插入到目标中 表

我已经看到所有这些方法都能解决类似场景中的性能问题;测试将揭示哪些数据可以为您提供最佳结果。

答案 3 :(得分:0)

显然,更改存储过程(通过重新编译)会改变导致锁定的环境。

尝试按照herehere所述记录SP的进度。

答案 4 :(得分:0)

如果您正在执行以下步骤:

DELETE table_y
INSERT INTO table_y <3 selects unioned together>

你可能想尝试这个

DROP TABLE table_y
SELECT INTO table_y <3 selects unioned together>

答案 5 :(得分:0)

我同意上面在评论中给出的答案,这听起来像是一个未公开的交易,特别是如果你仍然能够从查询分析器运行select语句。

听起来非常像有一个打开的事务,其中有一个挂起的table_y删除,并且此时插入不会发生。

当你的SP锁定时,你可以执行插入table_y吗?

答案 6 :(得分:0)

您是否有索引维护工作?

您的统计信息是最新的吗?一种说法是检查大变化的估计和实际查询计划。

答案 7 :(得分:0)

正如其他人所说,这听起来很可能是一项未提交的交易。

我最好的猜测:

您需要确保可以完全快速地删除table_y。

如果有其他存储过程或外部代码片段在此表上持有事务,您可能会永远等待。 (他们可能会错误并且永远不会关闭交易)

另一个注意事项:尽可能尝试使用truncate。它使用的资源少于没有where子句的删除:

truncate table table_y

此外,一旦您的OWN事务中发生错误,它将导致所有后续调用(显然每5分钟)“挂起”,除非您处理错误:

begin tran
begin try
 -- do normal stuff
end try
begin catch
 rollback
end catch
commit

第一个错误是为您提供有关实际错误的信息。看到它挂在你自己的后续测试中只是次要影响。