2013-02-27 21 views
7

我有一个存储过程,我使用LinqToSQL调用。我没有做任何特别的事情,例如Linq存储过程超时,但SSMS快速

MyDataContext db = new MyDataContext() 

var results = db.storedProcedure(param1, param2, param3) 

// Do stuff 

当我使用完全相同的参数运行存储过程时,我会在2到6秒之间得到结果。数据库是一个远程数据库。

但是,当我运行存储过程需要(调试后......)275秒!在正常情况下这给了以下异常:

[Win32Exception(0X80004005):等待操作超时]

[SQLEXCEPTION(0x80131904):超时过期。在操作完成之前已经超时或服务器没有响应。] System.Data.SqlClient.SqlConnection.OnError(SqlException异常,布尔breakConnection,操作1 wrapCloseInAction) +1753346 System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action 1 wrapCloseInAction)+5295154 System.Data.SqlClient.TdsParser .ThrowExceptionAndWarning(TdsParserStateObject stateObj,布尔callerHasConnectionLock,布尔asyncClose)242 System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior,SqlCommand的cmdHandler,SqlDataReader的数据流,BulkCopySimpleResultSet bulkCopyHandler,TdsParserStateObject stateObj,布尔& dataReady)1682 System.Data .SqlClient.SqlDataReader.TryConsumeMetaData()+59 System.Data.SqlClient.SqlDataReader.get_MetaData()+90 System.Data.SqlClient.SqlCommand.Finish的ExecuteReader(SqlDataReader的DS,RunBehavior runBehavior,字符串resetOptionsString)+ 365个 System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(的CommandBehavior cmdBehavior,RunBehavior runBehavior,布尔returnStream,布尔异步,的Int32超时,任务&任务,布尔asyncWrite)1325 系统.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior,RunBehavior runBehavior,Boolean returnStream,String method,TaskCompletionSource`1 completion,Int32 timeout,Task & task,Boolean asyncWrite)+175 System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior,RunBehavior runBehavior,布尔returnStream,String方法)+53 System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior行为,String方法)+134 System.Data.SqlClie nt.SqlCommand.ExecuteDbDataReader(CommandBehavior行为)+41 System.Data.Common.DbCommand.ExecuteReader()+12 System.Data.Linq.SqlClient.SqlProvider.Execute(表达式查询,QueryInfo queryInfo,IObjectReaderFactory工厂,Object [] parentArgs,Object [] userArgs,ICompiledSubQuery [] subQueries,Object lastResult)+1306 System.Data.Linq.SqlClient.SqlProvider.ExecuteAll(Expression query,QueryInfo [] queryInfos,IObjectReaderFactory factory,Object [] userArguments,ICompiledSubQuery [] subQueries )+118 System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query)+342 System.Data.Linq.DataContext.ExecuteMethodCall(对象实例,MethodInfo methodInfo,Object []参数)+83

所有其他存储过程都以相同方式调用,但都不存在此问题。远程数据库管理员说他可以在超时发生之前看到呼叫的开始和结束,所以它似乎与Linq接收数据之后的步骤有关。

有没有人遇到过这个以及任何想法如何解决它?

我已经尝试从dmbl文件中删除SP并重新添加它。它注意到其中一个值从小数变成了双倍,但除此之外它们都是一样的。

一如往常,这是昨天做工精细!

在此先感谢。

回答

3

好吧,我终于发现了真正的回答这个问题。 SSMS通常使用ARITHABORT ON和代码通常使用ARITHABORT OFF - 这基本上是对如何处理如果代码数学系有一个错误会发生什么的选项 - 例如除以零。

这里主要的事情,虽然是这两种方法有不同的执行计划 - 这就是为什么同样的事情可以(随机)的网站比SSMS上需要更长的时间。

执行计划是基于第一次使用它的估计值进行编译的,因此您随机找到的是执行计划以适合您的第一个查询的可怕方式进行缓存,但对于后续查询而言可怕。这就是发生在这里的事情,这也是为什么它突然重新开始工作 - 一个新的查询计划是在存储过程更改后创建的。

最后我们在存储过程中使用了WITH RECOMPILE - 因此没有有效的重用执行计划,但我们没有注意到任何差异,并且从那以后没有发生任何问题。

0

对我造成这个问题的原因是依赖于Linq的循环。表< > .Count()。在开发环境中,底层查询几乎是即时的,但在生产中需要几秒钟的时间。连接SQL事件探查器显示查询是在循环的每次迭代中执行的,所以这些“几秒钟”开始累加起来,并最终超时。

对我来说,解决办法是分配计数()产生一个局部变量,并用它在循环,使COUNT()没有重新执行每次迭代查询。我想如果他们依靠内置的Linq集合函数来重新执行慢查询,其他人将会遇到这个问题。