实体框架4调用存储过程超时。

17

我有一个存储过程导入到EF4中,当我使用特定的参数调用它时,30秒后会抛出超时错误。在SQL Server分析器中,我可以看到使用正确参数调用存储过程需要稍微超过30秒,这也是我的应用程序的超时时间。

但是当我在查询分析器中执行与分析器发送的相同的SQL时,执行时间少于一秒钟。是什么原因导致了从EF中调用和从SQL Server Management Studio中调用之间的差异?

.NET错误的完整堆栈跟踪如下所示。

[SqlException (0x80131904): 超时已过期。操作在完成之前超时或服务器未响应。]
System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) +2073486
System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) +5064444
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning() +234
System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) +2275
System.Data.SqlClient.SqlDataReader.ConsumeMetaData() +33
System.Data.SqlClient.SqlDataReader.get_MetaData() +86
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) +311
System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) +987
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) +162
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) +32
System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) +141
System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) +12
System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)+10 System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior) +443

[EntityCommandExecutionException: 在执行命令定义时发生错误。有关详细信息,请参见内部异常。]
System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior) +479
System.Data.Objects.ObjectContext.CreateFunctionObjectResult(EntityCommand entityCommand, EntitySet entitySet, EdmType edmType, MergeOption mergeOption) +182
System.Data.Objects.ObjectContext.ExecuteFunction(String functionName, MergeOption mergeOption, ObjectParameter[] parameters) +218
System.Data.Objects.ObjectContext.ExecuteFunction(String functionName, ObjectParameter[] parameters) +53
MetaView.DAL.MFCMData.MFCMDATAEntities.GetTradingOpenPositionCounterParty(Nullable1 positionDT, Nullable1 tradingAccountID) in C:\Projects\CASH\web\MetaView\MetaView.DAL.MFCMData\MFCMData.Designer.cs:7064 MetaView.BusinessLayer.Shared.Accounts.CounterParties.GetCounterParties(Int32 tradingAccountID) in C:\Projects\CASH\web\MetaView\MetaView.BusinessLayer\Shared\Accounts\CounterParties.cs:161


请发布查询和两个执行计划。 - usr
1个回答

26

我几周前遇到了类似的问题,我们的一位数据库管理员向我解释说:

当调用SQL Server存储过程时,服务器将为每个object_id缓存一个执行计划。有时候,SQL Server会根据传入的参数值(在我们的情况下是可为空的参数为null)创建错误的执行计划。当这种情况发生时,快速修复方法是在SQL Server Management Studio(或其他您使用的DB管理工具)中运行sp_recompile 'Schema.Procedure'。这只是清除该存储过程的计划缓存。如果下一个被调用的过程再次传递“错误”的参数值,则会陷入相同的情况,因此真正的解决办法是使用OPTIMIZE FOR语法为查询提示(请参见http://msdn.microsoft.com/en-gb/library/ms181714.aspx)。

简而言之,如果在WHERE和/或ORDER BY子句之后加入OPTION (OPTIMIZE FOR (@myParameter = 'Some value that gives you a GOOD execution plan')),它应该可以解决问题。

此外,如果您想知道为什么在SSMS中执行相同的SQL始终会获得快速结果,那是因为SSMS默认设置的ARITHABORT选项是ON(SET ARITHABORT ON),而其他所有应用程序都将其默认设置为OFF。但它的工作原理及其影响超出了我的经验范围,我也没有费心去了解它。不过,我被告知不应该使用它。我相信一个真正的数据库管理员可以更好地解释为什么。


1
回复:服务器会为每个存储过程每个调用应用程序(或每个连接字符串,我记不清了)创建并缓存一个执行计划。实际上,都不是。该计划是根据object_id进行缓存的,在临时SQL的情况下,object_id基于查询文本的哈希值生成(假设所有字符进行二进制比较)。 - Solomon Rutzky
我遇到了一个完全相同的问题,涉及到一个带有AS TABLE的函数,但是在这种情况下,选项(OPTIMIZE...)似乎不起作用。你有什么解决方法吗? - toregua
7
我在这里找到了一个解决方案:http://geekswithblogs.net/mknapp/archive/2011/12/09/mysterious-query-timeouts.aspx 这是一个与查询计划统计信息有关的问题。你需要在数据库属性中将"Auto Update Statistics Asynchronously"设置为TRUE。 - toregua
感谢toregua,我认为你的答案更加合适,不应该只是一条评论。另一个答案虽然在技术上很有趣,但可能不符合我的需求。我的存储过程查询不能有一个静态值可以使用——如果我留下记录来适应这个需求,我的应用程序状态就会混乱。其中一个OPTIMIZE FOR...关键字是UNKNOWN,但这似乎是默认值,不会改变太多。 - David Storfer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接