我有一个使用LinqToSQL调用的存储过程。我根本没做任何特别的事,例如
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异常,Boolean breakConnection,Action
1 wrapCloseInAction) +1753346 System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action
1 wrapCloseInAction)+5295154 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj,Boolean callerHasConnectionLock,Boolean 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.FinishExecuteReader(SqlDataReader ds,RunBehavior runBehavior,String resetOptionsString)+365 System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior,RunBehavior runBehavior,Boolean returnStream,Boolean async,Int32 timeout,Task& task,Boolean asyncWrite)+1325 System.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,Boolean returnStream,String method)+53 System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior,String method)+134 System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)+41 System.Data.Common.DbCommand.ExecuteReader()+ 12 System.Data.Linq.SqlClient.SqlProvider.Execute(Expression query,QueryInfo queryInfo,IObjectReaderFactory factory,Object [] parentArgs,Object [] userArgs,ICompiledSubQuery [] subQueries,Object lastResult)+1306 System.Data.Linq.SqlClient.SqlProvider.ExecuteAll(表达式查询,QueryInfo [] queryInfos,IObjectReaderFactory工厂,对象[] userArguments,ICompiledSubQuery []子查询)118 System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq .Provider.IProvider.Execute(表达式查询)+342 System.Data.Linq.DataContext.ExecuteMethodCall(Object instance,MethodInfo methodInfo,Object [] parameters)+83
以相同的方式调用所有其他存储过程,但没有一个存在此问题。远程数据库管理员说他可以在超时发生之前看到呼叫开始和结束,所以它似乎与Linq收到数据后的步骤有关。
以前有没有人经历过这个以及如何修复它?
我尝试从dmbl文件中删除SP并重新添加它。它注意到其中一个值从十进制变为双精度,但除此之外全部相同。
一如既往,昨天工作正常!
提前致谢。
答案 0 :(得分:3)
好的,我终于发现了这个问题的真实答案。 SSMS通常使用ARITHABORT ON并且代码通常使用ARITHABORT OFF - 这基本上是如何处理如果代码中的数学线有错误的情况的选项 - 例如除以零。
但这里的主要内容是两种方法都有不同的执行计划 - 这就是为什么同样的事情可以(随机)在网站上花费的时间比在SSMS中花费的时间长得多。
执行计划是根据第一次使用它的估计编译的,所以你随机发现的是执行计划以一种非常适合你的第一个查询的方式缓存,但后续查询却很糟糕。这就是这里发生的事情,这也是它突然重新开始工作的原因 - 在更改存储过程后创建了一个新的查询计划。
最后我们在存储过程中使用WITH RECOMPILE - 因此没有有效的重复使用执行计划,但我们没有注意到任何差异,并且此后没有发生问题。
答案 1 :(得分:0)
导致这个问题的原因是依赖于Linq.Table< > .Count之间()。在开发环境中,基础查询几乎是即时的,但在生产中需要几秒钟。连接SQL事件探查器后发现查询是在循环的每次迭代中执行的,因此那些“几秒钟”开始加起来,并最终超时。
我的解决方案是将Count()结果分配给局部变量,并在循环中使用它,以便Count()不会在每次迭代时重新执行查询。我想其他人会遇到这个问题,如果他们依赖内置的Linq聚合函数来重新执行慢查询。