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

cro*_*eym 30 t-sql sql-server ado.net timeout output-parameter

我有一个带签名的T-SQL存储过程

CREATE PROCEDURE MyProc
@recordCount INT OUTPUT
@param1 INT
...
Run Code Online (Sandbox Code Playgroud)

在Sql Server中直接执行时,该过程在5秒内运行,返回一些总计约100行的结果集.

调用使用ADO.NET此过程SqlDataAdapter.Fill方法来填充Dataset导致SqlTimeoutExceptionSqlCommand3分钟后(指定的超时间隔).

更改存储过程以使其不再具有输出参数,并且所需的输出值作为最后的结果集返回,解决了问题,并且整个过程在预期的5秒内运行.

但为什么?

我不想通过我的代码库来修改这种行为的所有实例,而不理解我是否真的解决了这个问题.

另一件需要注意的是,这只在一个特定的服务器上显而易见,它确实拥有比我们运行的其他类似数据库更大的数据集.肯定不是Sql Server设置?

UPDATE

进入框架源,问题似乎出现在元数据检索中.对象的ConsumeMetaData方法SqlDataReader无限期挂起.但是我在其他数据库上运行测试并且无法重现,因此当通过ADO.NET调用此过程时,这是一个特定于数据库的问题...很棒.

更新II

已确认如果我将代码更改为使用OleDbDataAdapterSQLOLEDB或SQLNCLI提供程序类型,则问题仍然存在.绝对与连接有关.

cro*_*eym 45

一旦我确定它是问题根源的ADO.NET连接,这个线程就引出了我的答案.

默认情况下,基本上通过Sql Server Management Studio(SSMS)连接具有SET ARITHABORT ON.ADO.NET连接没有.

ARITHABORT OFF直接通过SSMS 设置和执行查询给了我相同的慢响应时间.

使用或不使用此设置运行时的主要区别是为两个调用创建了不同的查询计划.什么ARITHABORT时候OFF,SSMS命令将使用ADO.NET连接正在使用的预编译缓存查询计划,因此超时.

通过在数据库上以管理员身份运行以下命令,无论ARITHABORT设置如何,所有查询都按预期运行.

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
Run Code Online (Sandbox Code Playgroud)

我只能假设编译的查询计划变得腐败或无效.

我会在另一个线程中使用此作为解决方案(我已经投了答案)

谢谢.

  • **警告**这个答案只是一个非常短期的修复,完全不必要的残酷.`DBCC DROPCLEANBUFFERS`将从缓存中删除大部分数据页,并且**没有效果**.`DBCC FREEPROCCACHE`将刷新整个过程缓存,只是为了删除一个有问题的计划!无法保证问题不会在未来的某个阶段再次发生.问题是参数嗅探.请参阅[本文](http://www.sommarskog.se/query-plan-mysteries.html)以获得更全面的解释. (19认同)
  • @StriplingWarrior 这里的另一篇好文章讨论了各种可能的预防措施 http://sqlperformance.com/2013/08/t-sql-queries/parameter-sniffing-embedding-and-the-recompile-options (2认同)
  • 在存储过程上使用 **WITH RECOMPILE;**。阅读:http://sqladvice.com/blogs/gstark/archive/2008/02/12/Arithabort-Option-Effects-Stored-Procedure-Performance.aspx (2认同)