SqlDataAdapter.Fill() 超时 - 底层存储过程快速返回

问题描述 投票:0回答:10

我有一个 SqlDataAdapter,其中填充了 21 行数据(4 列)。驱动它的存储过程在 SQL Mgmt Studio 中几秒钟内返回,但 .Fill() 需要 5 分钟。

    ArrayList ret = new ArrayList();
    SqlDataAdapter da = null;
    SqlCommand cmd = null;  
        cmd = base.GetStoredProc("usp_dsp_Stuff"); //Returns immediately in MSSMS.
        cmd.CommandTimeout = 3600; // Set to 6 min - debug only
        base.AddParameter(ref cmd, "@Param1", ParameterDirection.Input, SqlDbType.BigInt, 8, 19, 0, theParam1);
        base.AddParameter(ref cmd, "@Param2", ParameterDirection.Input, SqlDbType.BigInt, 8, 19, 0, theParam2);
        base.AddParameter(ref cmd, "@Param3", ParameterDirection.Input, SqlDbType.Char, 1, 'C');
        da = new SqlDataAdapter(cmd);
        DataTable dt = new DataTable();
        da.Fill(dt); //Takes 5 minutes.

有什么想法吗?

提前致谢! -克里斯

sql timeout dataadapter fill
10个回答
8
投票
da = new SqlDataAdapter(cmd);
da.SelectCommand.CommandTimeout = 1800;

5
投票

最近,我就经历了这样的情况:

.Fill
超时,但相同的 SP 在 SQL Server Management Studio 中速度超快。这是因为您的 .NET 应用程序创建 SQL 连接并使用
SET ARITHABORT OFF
,而 SQL Server Management Studio 默认情况下使用
SET ARITHABORT ON
。这会导致使用两个不同的执行计划,因此您无法在 SQL Server Management Studio 中重现此超时。我建议您检查一下您的 SP 并进行一些更改。


4
投票

谢谢您的帮助。解决方案是在存储过程正在使用的连接上添加 with (nolock) 语句:

FROM Category_tbl c INNER JOIN dbo.categoryItem_LNK cl with (NOLOCK) ON c.categoryid = cl.categoryid

我不知道为什么我们在使用 SqlDataAdapter 时只看到性能下降,但是这个改变立即解决了问题。

再次感谢, 克里斯


3
投票

我知道这已经太晚了,好像晚了7年!但我今天遇到了这个问题并想分享我的解决方案。在我的实例中,从 SQL 中提取的数据是一个表值函数。表值函数仅返回大约 3500 行,花费时间不到 1 秒,但在 C# 代码中的 Fill() 上超时。我不知道它是谁或如何工作的,但删除并重新创建该函数修复了它。我认为这与 .NET 如何读取 SQL 给出的数据有关,就像在报表中使用视图后对其进行更改时需要重新创建视图的方式一样。再说一遍,我不是 100% 确定幕后发生了什么,但对我来说这是一个快速修复


1
投票

糟糕的查询计划和参数嗅探。对于存储过程,尤其是参数会大幅调整读取的行的存储过程,原因是查看传入参数时出现了错误的执行计划。由于 SET 参数不同,在 SQL Management Studio 中不会发生这种情况。

这个帖子很好地总结了您的问题: http://social.msdn.microsoft.com/Forums/en-US/transactsql/thread/9fd72536-f714-422a-b4c9-078e2ef365da/

这是一个典型的参数案例 嗅探。您的申请最有可能 使用不同的 SET 选项运行(设置 通过客户端API)并使用 与执行计划不同的执行计划 在 SSMS 中创建。发生的情况是当 你的程序是调用第一个 通过您的应用程序创建的时间 根据参数执行计划 通过了。然而,这个执行计划 可能不适合另一组 参数,这可能会导致效果不佳 执行时的性能 其他参数组。请参阅 以下为更多详细信息和 不同的解决方案: http://pratchev.blogspot.com/2007/08/parameter-sniffing.html

这里有更多关于计划缓存和查询计划重用的内部结构:
http://technet.microsoft.com/en-us/library/cc966425.aspx


1
投票

我不想透露这个消息,但是(NOLOCK)不是一个解决方案,它只会产生新问题,例如脏读、丢失/重复的数据,甚至中止的查询。 SQL 数据库中的锁是您的朋友。

如果锁定(或更糟糕的是阻塞)导致速度变慢,您可以比较通过 SSMS 运行的连接选项和应用程序使用的连接选项。使用 SQL Profiler 查看代码是如何执行的。

如果这些字段中的任何一个是大型对象,请记住 SSMS 默认情况下仅自动检索几百个字符。返回的额外数据可能是一个因素。


0
投票

Fill() 有时可能会很慢,因为 .NET 正在分析从过程返回的数据。

使用 SQL Profiler 计算出执行 Fill() 时 SQL .NET 实际发送的内容。

如果是发送很多SET语句,比如

设置 concat_null_yields_null 为 on
将cursor_close_on_commit设置为关闭
将implicit_transactions设置为关闭

ETC...

..然后将这些相同的 set 语句放入您的存储过程中可能会加快速度。


0
投票
我使用了以下代码,其持续时间是 sqlCommclass.CommandTimeout 我在da.Fill(dt)之前添加是因为请求时间超过10分钟

using (SqlConnection myADONETConnection = new SqlConnection(vendor.Value)) { using (SqlDataAdapter da = new SqlDataAdapter("", myADONETConnection)) { .. .. .. da.SelectCommand = sqlCommclass; sqlCommclass.CommandTimeout = 30000; da.Fill(dt); } }
    

0
投票
其他解决方案对我不起作用。起作用的是添加

OPTION(RECOMPILE)

在我的查询结束时,如下所示:
https://stackoverflow.com/a/14120510/1621118


0
投票
就我而言,问题是相应表上的锁。 (nolock)没有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.