所以我在一个有10年历史的系统上使用了一个大型数据库(30gig)sql2005和一个.net 3.5 web前端。它有新的和旧的比特
我们遇到的问题越来越频繁。
一个存储的proc(到目前为止我们已经有4个不同的proc)决定它将超时。调用发生在Web服务器上,并达到30秒超时,并记录到我们的错误日志中。该网站使用单一登录(我知道这是错误的,但由于遗留代码,无法更改)。
就在这之后,我运行完全相同的呼叫,它需要(以我的身份登录)1秒。
这个问题仍然存在于这个存储过程中,直到我们删除并重新创建它,导致大量超时。每个sp调用都有不同的参数。在get-me中,与当前用户有关的所有未签名的偏移,因此当前用户作为参数传入
这个解决方案有效,但我真的不明白为什么。
我们的发布周期是两周,这个错误随时都会发生。它发生在发布一周后的第二天,最后一次是发布12天后。
在每个版本中,我们对所有存储的进程/触发器/函数/视图执行SQL多脚本,每次删除并重新创建自己。
我所能想到的是,存储过程执行计划已经损坏/出错,删除并重新创建它可以清除这一点。
我正在考虑调用sps WITH RECOMPILE选项,这是否??或绕过的可接受方式
这听起来很像我一次又一次看到的问题-存储过程计划已从计划缓存中刷新,下次运行该过程时,传入的参数会产生一个计划,该计划可能对该组参数很好,但对其他组合却表现不佳。
如果你有"可选"参数,其中NULL或可能会传递一个值,并且你在WHERE
子句中使用OR
来处理这个问题,那么这通常会导致这种情况。
WITH RECOMPILE可能会导致每次编译计划时占用大量CPU-如果存储过程被调用很多,那么这很容易对服务器的总体性能产生影响-坏计划的影响是否会超过这一操作系统是另一回事。
通常,最好尝试重写查询-如果您使用OR
来处理不同的参数集,那么动态SQL(以正确的方式使用sp_executesql和参数)会有很大帮助。
附言:关于存储过程在运行时运行良好的问题-我也看到了这一点-我认为这是因为生成了不同的计划-我一直怀疑,运行例如SSMS时启用的SET
选项集与(在我的例子中).Net略有不同-并且在这个例子中,计划是单独缓存的。如果有人能证实这可能发生,我们将不胜感激!
我怀疑是存储过程直接导致了这种情况,除非它正在执行某种未清理的锁定/事务逻辑。即便如此,我也看不出丢弃/重新创建会对这件事产生什么影响。我可能会查看SP正在使用的数据,并尝试使用分析来跟踪它的执行路径,看看性能是否可以提高。
这很可能是为特定proc存储的错误执行计划的结果。
问题(简化)在于SQL server试图根据传递的参数优化执行计划的使用。在某些情况下,这可能会导致糟糕的表现。
下面是一些阅读资料来进一步解释。
http://blogs.msdn.com/b/queryoptteam/archive/2006/03/31/565991.aspx
http://elegantcode.com/2008/05/17/sql-parameter-sniffing-and-what-to-do-about-it/
从好的方面来看,通过将proc中传递的参数复制到局部变量来修复它非常简单。