过程在 ADO.NET 中超时,但在 SSMS 中没有

Posted

技术标签:

【中文标题】过程在 ADO.NET 中超时,但在 SSMS 中没有【英文标题】:Procedure times out from ADO.NET but not in SSMS 【发布时间】:2011-10-29 03:08:41 【问题描述】:

我有一个存储过程,它给我一个 SqlException,因为当我从代码运行它时超时(超时设置为 30)。 当我直接在 Management Studio 中运行该过程时,它会在 1 秒内执行。 我也只有在针对特定数据库运行时才会超时。 当我使用其他数据库时,它会快速完成而不会出现错误。 以下是完整的错误信息:

System.Data.SqlClient.SqlException (0x80131904): Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
   at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   at System.Data.SqlClient.SqlDataReader.ConsumeMetaData()
   at System.Data.SqlClient.SqlDataReader.get_MetaData()
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
   at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
   at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
   at System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader(CommandBehavior behavior)

这个堆栈跟踪对任何人来说都意味着什么吗?看起来我的存储过程可能已完成,但在尝试读取某种元数据时超时?

我尝试在进程运行时查看它,但它已暂停。 sys.dm_os_waiting_tasks 将等待类型显示为 IO_COMPLETION(如果有任何用处)。我使用 sp_who2 'active' 在数据库上看到的唯一进程是一个超时和我的活动 SSMS 窗口,所以我不认为这是一个阻塞问题。我验证了该数据库与工作数据库具有相同的索引,并且运行 dbcc checkdb 没有任何错误。如何确定超时原因?

【问题讨论】:

您是否使用与您的应用程序相同的凭据登录 SSMS? Query times out from web app but runs fine from management studio 的可能重复项 可能。您可以在这里查看我对类似问题的回答***.com/questions/5553967/… 这也是一个很好的方法,但是我不想重新编写我的所有程序来将输入参数值传递给局部变量。 OP 的问题似乎是 ARITHABORT 设置的差异,但实际上可能是任何 SET 选项导致不同的计划。 大卫,我在 SSMS 中使用我的 Windows 帐户,但使用的是应用程序中的 SQL 用户。不过,请参阅我对以下答案的回复。 【参考方案1】:

您可以将超时会话的 SET 选项与未超时会话的 SET 选项进行比较:

SELECT
    session_id,
    [ansi_defaults],
    [ansi_null_dflt_on],
    [ansi_nulls],
    [ansi_padding],
    [ansi_warnings],
    [arithabort],
    [concat_null_yields_null],
    [deadlock_priority],
    [quoted_identifier],
    [transaction_isolation_level]
FROM
    sys.dm_exec_sessions
WHERE
    session_id IN (<spid1>, <spid2>);

当您发现一些不同时,尝试在 SSMS 查询中将每个设置更改为相反的设置,直到您获得超时(或在发送查询之前手动设置应用代码中的选项)。现在,我手边没有 2005 实例,所以没有测试这个查询。您可能需要注释掉一个或多个列名。

【讨论】:

谢谢亚伦。唯一的区别是 arithabort 不在应用程序中。我尝试将其设置为打开,但它并没有加快速度。我需要从上面的帖子中澄清一个细节,因为我似乎做出了错误的假设。在 SSMS 中,我通过硬编码其参数来执行 SQL from 存储过程。我发现如果我真的在 SSMS 中执行存储过程并传入参数,运行需要 35-38 秒,这会超时。那么为什么运行 SQL 会立即执行,但通过 sproc 运行却要慢 35 倍呢? 您需要检查执行计划。由于当时的统计数据不同、非典型参数等原因,缓存的计划可能不是最优的。尝试将 WITH RECOMPILE 添加到存储过程(或删除它并重新创建它)以查看是否有任何对性能的影响。 执行计划确实略有不同(我真的不知道我在看什么)。在有效的循环中有一个嵌套循环,在另一个循环中存在哈希匹配,并且一些成本百分比不同。所以我放弃并重新创建了它。这使得它在 SSMS 之外快速执行并且运行速度足够快,不会超时应用程序,但在应用程序中仍然需要 20-25 秒。在进行更多测试以查看现在是否是 arith abort 问题时,我再次更改了存储过程,现在它在 SSMS 和 SQL 中又回到了 30 秒以上。【参考方案2】:

删除并重新创建 SP 将清除损坏的缓存执行计划

DROP PROCEDURE [dbo].[YourSPName]
GO
CREATE PROCEDURE [dbo].[YourSPName]
-- your SP Code

【讨论】:

以上是关于过程在 ADO.NET 中超时,但在 SSMS 中没有的主要内容,如果未能解决你的问题,请参考以下文章

存储过程如何在从 BIDS 调用时不返回行,但在使用相同参数时从 SSMS 调用时返回行?

在SSMS中超链接SQL Server查询结果中的值

WCF 命名管道在 WinApp 中超时,但在 ConsoleApp 中没有?

ODBC 查询在 MS Access 中有效,但在 SQL Server 中超时

ADO.NET 调用 T-SQL 存储过程会导致 SqlTimeoutException

如何在 ASP.NET Core MVC 中使用 ADO.NET 向存储过程添加参数?