我有一个导入EF4的存储过程,当我在30秒后用某些参数调用它时会抛出超时错误。在SQL Server探查器中,我可以看到存储过程调用使用适当的参数只需要超过30秒,这是我的应用程序的超时。
然而,当我执行在查询分析器中发送到探查器的相同SQL时,它会执行亚秒级。什么可能导致从EF调用和从SQL Server Management Studio调用之间的差异?
以下是.NET错误的完整堆栈跟踪。
[SqlException(0x80131904):超时已过期。超时期限 在完成操作之前经过或服务器没有经过 响应。]
System.Data.SqlClient.SqlConnection.OnError(SqlException异常, 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 方法,DbAsyncResult结果)+162
System.Data.SqlClient.SqlCommand.RunExecuteReader(的CommandBehavior cmdBehavior,RunBehavior runBehavior,Boolean returnStream,String 方法)+32
System.Data.SqlClient.SqlCommand.ExecuteReader(的CommandBehavior 行为,字符串方法)+141
System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(的CommandBehavior 行为)+12
System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior) +10 System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand) entityCommand,CommandBehavior行为)+443[EntityCommandExecutionException:执行时发生错误 命令定义。有关详细信息,请参阅内部异常。]
System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand,CommandBehavior行为)+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 []参数)+53
MetaView.DAL.MFCMData.MFCMDATAEntities.GetTradingOpenPositionCounterParty(Nullable1 positionDT, Nullable
1 tradingAccountID)in C:\项目\ CASH \网络\ MetaView \ MetaView.DAL.MFCMData \ MFCMData.Designer.cs:7064 MetaView.BusinessLayer.Shared.Accounts.CounterParties.GetCounterParties(的Int32 tradingAccountID)in C:\项目\ CASH \网络\ MetaView \ MetaView.BusinessLayer \共享\帐户\ CounterParties.cs:161
答案 0 :(得分:24)
所以几个星期前我遇到了类似的问题,这是我们的一位DBA向我解释的(当然是转述和愚蠢):
当调用SQL Server存储过程时,服务器会为每个存储过程 per object_id
创建并缓存执行计划。有时,SQL Server可以创建一个错误的执行计划,具体取决于传入的参数值(在我们的例子中,对于可为空的参数,它是null)。发生这种情况时,快速解决方法是在SQL Server Management Studio(或您可能使用的任何数据库管理工具)中运行sp_recompile 'Schema.Procedure'
。所有这一切都清楚了该存储过程的计划缓存。如果proc的下一个被调用者再次传入“bad”参数值,那么你将陷入相同的情况所以真正的解决方法是使用OPTIMIZE FOR
为查询提供一个提示语法(参见http://msdn.microsoft.com/en-gb/library/ms181714.aspx)。
简而言之,如果您在OPTION (OPTIMIZE FOR (@myParameter = 'Some value that gives you a GOOD execution plan'))
和/或WHERE
条款之后添加ORDER BY
,则应该解决问题。
此外,如果您想知道为什么在SSMS中执行相同的 SQL时,您总能获得快速的结果,因为SSMS对于名为ARITHABORT的选项(SET ARITHABORT ON
的默认设置为ON )所有其他应用程序默认设置为关闭,但它是如何工作的,其含义超出了我的经验,我没有费心去阅读它。有人告诉我,我不应该使用它。我确信真正的DBA可以更好地解释原因。