当从Web上调用存储过程时,速度很慢,来自Management Studio

我有存储过程疯狂超时每一次从Web应用程序调用它。

我启动了Sql Profiler并追踪了超时的调用,最后发现了这些事情:

  1. 当从MS SQL Management Studio中执行语句时,使用相同的参数(实际上,我从sql profile trace复制过程调用并运行它):在5〜6秒内完成平均。
  2. 但是,当从Web应用程序调用,它需要超过30秒(跟踪),所以我的网页实际上超时了。

除了我的Web应用程序有自己的用户,每一件事情都是一样的(相同的数据库,连接,服务器等),我也试着直接在工作室与Web应用程序的用户运行查询,它不会超过6秒。

我如何知道发生了什么?

我假设它与我们使用BLL> DAL层或表适配器的事实无关,因为跟踪清楚地显示了延迟在实际过程中。 这是我所能想到的。

编辑我在这个链接中发现,ADO.NET设置ARITHABORT为真 – 这对大多数时间是好的,但有时会发生这种情况,build议的解决方法是添加with recompile选项存储过程。 在我的情况下,它不工作,但我怀疑这是非常相似的东西。 任何人都知道还有什么ADO.NET做什么或我可以find规范?

过去我也有类似的问题,所以我很想看到这个问题的解决scheme。 Aaron Bertrand对OP的评论导致查询从网页执行时超时,但是从SSMS执行时超快 ,虽然问题不是重复的,但答案可能很适用于您的情况。

实际上,这听起来像SQL Server可能有一个腐败的caching执行计划。 你正在用你的web服务器打坏计划,但是由于在ARITHABORT标志上有一个不同的设置(否则这个设置对你的特定的查询/存储过程没有影响),所以SSMS登陆了一个不同的计划。

请参阅调用T-SQL存储过程的ADO.NET导致SqlTimeoutException另一个示例,具有更完整的解释和解决scheme。

我也体验到,查询从网上运行缓慢,在SSMS中运行速度很快,最终我发现问题是所谓的参数嗅探。

对我来说,解决的办法是将sproc中使用的所有参数改为局部variables。

例如。 更改:

 ALTER PROCEDURE [dbo].[sproc] @param1 int, AS SELECT * FROM Table WHERE ID = @param1 

至:

 ALTER PROCEDURE [dbo].[sproc] @param1 int, AS DECLARE @param1a int SET @param1a = @param1 SELECT * FROM Table WHERE ID = @param1a 

似乎很奇怪,但它解决了我的问题。

难道在Web应用程序调用SP之前进行的其他一些DB调用是否保持事务处于打开状态? 这可能是此SP等待Web应用程序调用时的原因。 我说隔离在Web应用程序中的调用(把它放在一个新的页面),以确保在Web应用程序中的一些先前的行动是造成这个问题。

不是垃圾邮件,但作为一个有希望的解决scheme,我们的系统看到了高度的超时。

我试着设置存储过程使用sp_recompile重新编译,这解决了一个SP的问题。

最终有更多的SP超时,其中许多从来没有这样做过,通过使用DBCC DROPCLEANBUFFERSDBBC FREEPROCCACHE ,超时事件发生率明显下降 – 仍然存在孤立事件,有些我怀疑计划再生需要一段时间,还有一些SP的真正欠佳,需要重新评估。

简单地重新编译存储过程(我的例子中的表函数)为我工作

像@赞说,这可能是由于参数嗅探。 我经历了同样的行为,我看了一下过程的执行计划和一行中的所有sp的语句(复制所有的语句形成过程,将参数声明为variables,并赋值为variables的相同值参数已经)。 但执行计划看起来完全不同。 sp执行需要3-4秒钟,并且具有完全相同值的报表立即返回。

executionplan

经过一些Googlesearch之后,我发现了一个关于这个行为的有趣阅读: 在应用程序中慢,在SSMS中快速?

在编译过程时,SQL Server不知道@fromdate的值会发生变化,但会在假设@fromdate的值为NULL的情况下编译该过程。 由于所有与NULL的比较产生UNKNOWN,如果@fromdate在运行时仍然有这个值,查询就根本不能返回任何行。 如果SQL Server将input值作为最终的事实,它可以构造一个只有恒定扫描的计划,根本不访问表(运行查询SELECT * FROM Orders WHERE OrderDate> NULL来查看一个例子) 。 但SQL Server必须生成一个计划,无论运行时@fromdate具有什么值,都会返回正确的结果。 另一方面,没有义务build立一个对所有价值都是最好的计划。 因此,由于假定没有行将被返回,所以SQL Server将为索引search寻求解决办法。

问题是我有参数可以留空,如果他们被传递为null将被初始化一个默认值。

 create procedure dbo.procedure @dateTo datetime = null begin if (@dateTo is null) begin select @dateTo = GETUTCDATE() end select foo from dbo.table where createdDate < @dateTo end 

我改变后

 create procedure dbo.procedure @dateTo datetime = null begin declare @to datetime = coalesce(@dateTo, getutcdate()) select foo from dbo.table where createdDate < @to end 

它再次像魅力一样工作。