使用ADO.Net的查询的连接超时异常

时间:2020-03-06 14:27:51  来源:igfitidea点击:

更新:看起来查询不会引发任何超时。连接超时。

这是用于执行查询的示例代码。有时,在执行耗时的查询时,它将引发超时异常。

我不能使用以下任何一种技术:
1)增加超时时间。
2)使用回调异步运行它。这需要以同步方式运行。

请建议其他任何技术来在执行耗时的查询时保持连接畅通吗?

private static void CreateCommand(string queryString,
    string connectionString)
{
    using (SqlConnection connection = new SqlConnection(
               connectionString))
    {
        SqlCommand command = new SqlCommand(queryString, connection);
        command.Connection.Open();
        command.ExecuteNonQuery();
    }
}

解决方案

command.CommandTimeout *= 2;

这将使默认超时(30秒)增加一倍。

或者,将CommandTimeout的值放在配置文件中,以便我们可以根据需要进行调整而无需重新编译。

如果绝对不能增加超时,则唯一的选择是减少查询在默认30秒超时内执行的时间。

我们应该将查询分为多个块,每个块在超时时间内执行。

我必须同意Terrapin。

我们可以选择几种方法来减少时间。首先,如果公司雇用DBA,我建议我们向他们征求建议。

如果这不是一个选择,或者我们想首先尝试其他一些事情,那么这里有三个主要选择:

  • 将查询分解为在超时下运行的组件。这可能是最简单的。
  • 更改查询以优化通过数据库的访问路径(通常:尽可能接近索引)
  • 更改或者添加索引以影响查询的访问路径。

我们应该首先检查查询,以查看查询是否经过优化,并且在丢失的索引上无法运行。对于大多数查询,即使对大型数据库进行了适当调整,也可以分配30秒的时间。如果使用查询计划有充分的证据证明查询的执行时间不能超过此时间,则应该增加超时时间,没有其他方法可以保持连接,这是超时的目的,如果查询未在该时间范围内完成。

如果我们无法使用更改超时值的默认过程,那么我们很可能需要做更多的工作。想到以下选项

  • 与DBA和其他代码审核一起验证我们是否已尽可能最佳地优化了查询
  • 在基础数据库结构上进行工作,以查看是否可以从数据库方面获得任何收益,从而创建/修改一个等值线。
  • 将其分为多个部分,即使这意味着运行带有多个返回参数的过程,这些返回参数只是简单地调用了另一个参数。 (此选项不是很好,老实说,如果代码真的要花这么多时间,我将去管理并重新讨论30秒的超时时间)

最近,我们在SQL Server 2000数据库上遇到了类似的问题。

在查询期间,请在db服务器上的master数据库上运行此查询,并查看是否有任何锁应进行故障排除:

select 
  spid,
  db_name(sp.dbid) as DBname,
  blocked as BlockedBy,
  waittime as WaitInMs,
  lastwaittype,
  waitresource,
  cpu,
  physical_io,
  memusage,
  loginame,
  login_time,
  last_batch,
  hostname,
  sql_handle
from sysprocesses sp
where (waittype > 0 and spid > 49) or spid in (select blocked from sysprocesses where blocked > 0)

SQL Server Management Studio 2008还包含一个非常酷的活动监视器,它使我们可以在查询期间查看数据库的运行状况。

在我们的例子中,这是一个网络锁,使数据库忙碌。这是一些旧的VB代码,并没有足够快地断开其结果集。

我倾向于不喜欢增加连接/命令超时,因为在我看来这是照顾症状而不是问题的问题

由于我们正在使用不返回任何行的ExecuteNonQuery,因此可以尝试这种基于轮询的方法。它以异步方式执行查询(没有回调)
但应用程序将等待(在while循环内)直到查询完成。从MSDN。这样可以解决超时问题。请尝试一下。

但是,我同意其他人的意见,我们应该多考虑优化查询以在30秒内执行。

IAsyncResult result = command.BeginExecuteNonQuery();

        int count = 0;
        while (!result.IsCompleted)
        {
            Console.WriteLine("Waiting ({0})", count++);
            System.Threading.Thread.Sleep(1000);
        }
        Console.WriteLine("Command complete. Affected {0} rows.",
        command.EndExecuteNonQuery(result));

如果禁止我们使用数据访问API的功能来允许查询持续超过30秒,那么我们需要查看SQL。

与优化SQL相比,通过优化ADO.NET的使用所获得的性能提升是微不足道的。

而且我们已经在使用执行SQL的最有效方法。其他技术可能会让人觉得麻木(尽管,如果我们使用DataSets快速检索了行并使用了一些非常慢的客户端处理功能,则可能可以将初始检索时间缩短到30秒以内,但我对此表示怀疑。 )

如果我们知道我们是否正在执行插入,那么也许我们应该使用批量插入。但是我们不知道sql的内容。

只需将sqlcommand的CommandTimeout属性设置为0,这将导致命令等待查询完成...
例如:

SqlCommand cmd = new SqlCommand(spName,conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 0;

这是一个丑陋的骇客,但在我们可以解决实际问题之前,可能会暂时帮助解决问题

private static void CreateCommand(string queryString,string connectionString)
    {
        int maxRetries = 3;
        int retries = 0;
        while(true)
        {
            try
            {
                using (SqlConnection connection = new SqlConnection(connectionString))
                {
                    SqlCommand command = new SqlCommand(queryString, connection);
                    command.Connection.Open();
                    command.ExecuteNonQuery();
                }
                break;
            }
            catch (SqlException se)
            {
                if (se.Message.IndexOf("Timeout", StringComparison.InvariantCultureIgnoreCase) == -1)
                    throw; //not a timeout

                if (retries >= maxRetries)
                    throw new Exception( String.Format("Timedout {0} Times", retries),se);

                //or break to throw no error

                retries++;
            }
        }
    }

我们是否考虑过将查询分为几个较小的块?

另外,我们是否在以下位置针对数据库引擎优化顾问运行了查询:

Management Studio>工具>数据库引擎优化顾问

最后,我们可以看看查询本身吗?

干杯

我们是否尝试过将SQL包装在存储过程中,它们似乎具有更好的内存管理。在使用经典ADO进行内部查询的计划sql语句中,以前已经看到过类似的超时问题。即从内部连接somthingTable中选择*。内部查询返回大量结果的位置。

其他技巧
1.使用with(nolock)执行提示执行读取,这很脏,我不建议这样做,但是它会更快。
2.还要查看我们尝试运行并减少行扫描(连接表的顺序)的sql的执行计划。
3.查看在表中添加一些索引以加快读取速度。
4.我还发现删除行非常昂贵,我们可以尝试限制每个调用的行数。
5.在过去,用#temporary表交换@table变量也对我有用。
6.我们可能还保存了错误的执行计划(听说过,从未见过)。

希望这可以帮助

Update: Looks like the query does not
  throw any timeout. The connection is
  timing out.

I.o.w.,即使我们不执行查询,连接也会超时吗?因为有两个超时:连接和查询。每个人似乎都专注于查询,但是如果出现连接超时,则是网络问题,并且与查询无关:显然,必须首先建立连接,然后才能运行查询。

可能值得尝试分页返回结果。