31

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

CREATE PROCEDURE MyProc
@recordCount INT OUTPUT
@param1 INT
...

当直接在 Sql Server 中执行时,该过程在 5 秒内运行,返回几个结果集,总计约 100 行。

使用 ADO.NETSqlDataAdapter.Fill方法调用此过程以填充 aDataset会导致 aSqlTimeoutExceptionSqlCommand3 分钟后(指定的超时间隔)。

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

但为什么?

我不想在不了解我是否真的解决了问题的情况下浏览我的代码库并修改此类行为的所有实例。

另一件需要注意的是,这仅在一个特定的服务器上很明显,该服务器的数据集比我们运行的其他类似数据库要大。肯定不是 Sql Server 设置?

更新

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

更新二

已确认如果我将代码更改为OleDbDataAdapter与 SQLOLEDB 或 SQLNCLI 提供程序类型一起使用,问题仍然存在。肯定跟关系有关。

4

3 回答 3

48

一旦我确定问题的根源是 ADO.NET 连接,这个线程就会引导我找到答案。

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

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

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

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

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE

我只能假设已编译的查询计划已损坏或无效。

我将在另一个线程上将此作为解决方案(我已对答案投了赞成票)

谢谢。

于 2009-05-08T09:45:03.657 回答
1

我的立场是正确的 - 是的,你可以同时拥有 - 一个OUTPUT参数以及一组被返回的行。你每天学习新的东西 :-)

至于为什么会发生超时 - 嗯....很难说。一个快速的小样本对我来说很好。你能发布你的存储过程(至少是它的相关部分)吗?

我们在谈论多少行,在这里返回?

在存储过程中的什么时候,您正在计算需要作为 OUTPUT 参数返回的行数?

如果您尝试将另一个参数添加MaxRows到您的 SProc 作为测试并对SELECT TOP (@MaxRows).......您的数据进行测试,该怎么办?这会很快回来吗?

马克

于 2009-05-07T11:34:34.930 回答
0

简而言之 - 我通过强制 SQL Server 使用最合适的索引来限制 lob 逻辑读取来解决我的问题,因为它无法自行解决。

在长 -

在尝试了所有其他建议的答案后,我刚刚遇到了这个问题并以不同的方式解决了它。在 SSMS 中,查询在约 3 秒内运行,但在从 .Net MVC Web 应用程序调用时超时。

SSMS 中的统计信息 IO 输出告诉我,一张表上有超过 195,500,000 次 lob 逻辑读取(具有聚集列存储索引的 20M 行表,也有行索引,但没有“LOB”列)。我从执行计划中注意到,大部分负载 (76%) 来自对其中一个行索引的索引查找。我使用了以下内容:

from [table] with (index([clustered columnstore index name]))

在我的查询中强制使用聚集列存储索引,我的查询减少到 <1s,lob 逻辑读取从 >195M 下降到 <6k,现在从 web 应用程序调用 SP 时,它是往返1.3 秒。

我尝试了选项重新编译,设置 arithabort,参数嗅探,最后 SQL Server 只是无法确定要使用哪个索引。顺便说一句,这也是一个极端情况,也是我唯一一次不得不在这个数据库中强制索引。

于 2016-10-24T16:15:46.477 回答