【问题标题】:Connection Timeout exception for a query using ADO.Net使用 ADO.Net 的查询的连接超时异常
【发布时间】:2008-09-19 21:08:46
【问题描述】:

更新:查询似乎没有引发任何超时。连接超时。

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

不能使用以下任何技术: 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();
    }
}

【问题讨论】:

  • 对不起,我需要澄清一下:为什么不能增加超时时间?
  • 这是违反公司标准的。 :( 我尝试尽可能多地优化查询,但仍然需要一些时间..
  • 如果你不能增加超时时间,也不能减少执行时间,而且你必须同步进行,那么你就定义了一个无法解决的问题。
  • 也许您应该发布查询计划,如果可以调整查询,我们可以给您一些提示...
  • 您的查询是否始终超时,或者它是临时的,即有时它工作有时它不工作。如果它是临时的,我可以给你一些我们为类似死锁问题所做的代码。

标签: c# .net ado.net timeout


【解决方案1】:

由于您使用的是不返回任何行的 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));

【讨论】:

  • 谢谢。这似乎工作。如果有更好的结果会再等一段时间..
  • 检查结果。IsCompleted 是多余的。
  • OP 指出是该查询超时。无论是同步还是异步,查询超时问题仍然相同。例如,在您的查询中输入 WAITFOR DELAY '00:01:00'。如果你的 command.Timeout 是 30 秒,这仍然会在 30 秒时引发查询超时,无论是异步调用还是同步调用。
  • @stephbu - 看起来查询没有超时。这是超时的连接。这个解决方案目前运行良好。
  • 我不是 100% 确定,但我认为 SqlConnection 不会超时 - 据我所知,只有打开新连接可能会超时(默认为 15 秒)。所以我仍然相信命令超时(如果命令在尝试从连接中读取时超时,这可能看起来像连接超时。)。
【解决方案2】:

您应该首先检查您的查询,看看它是否经过优化,并且它没有以某种方式在缺少的索引上运行。 为大多数查询分配 30 秒,即使在经过适当调整的大型数据库上也是如此。如果您使用查询计划有充分的证据表明查询不能比这更快地执行,那么您应该增加超时,没有其他方法可以保持连接,这就是超时终止连接的目的,如果查询未在该时间范围内完成。

【讨论】:

    【解决方案3】:

    我必须同意 Terrapin。

    您可以通过多种方式来减少时间。首先,如果贵公司雇用 DBA,我建议向他们征求建议。

    如果这不是一个选项,或者如果您想先尝试其他一些事情,这里是您的三个主要选项:

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

    【讨论】:

      【解决方案4】:

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

      1. 通过您的 DBA 和另一次代码审查来验证您已经尽可能地优化了查询
      2. 处理底层数据库结构,看看您是否可以在数据库方面获得任何收益,创建/修改一个 idex。
      3. 将它分成多个部分,即使这意味着运行具有多个返回参数的过程,这些参数只是调用另一个参数。 (这个选项并不优雅,老实说,如果你的代码真的要花这么多时间,我会去管理并重新讨论 30 秒超时)

      【讨论】:

      • 真的。问题是管理层希望我探索所有选择。 :)
      【解决方案5】:

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

      在查询期间,在 db 服务器上的主数据库上运行此查询,看看是否有任何锁需要解决:

      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 代码,它没有足够快地断开其结果集。

      【讨论】:

        【解决方案6】:

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

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

        而且您已经在使用最有效的 SQL 执行方法。其他技术的速度会慢得多(尽管,如果您使用 DataSet 快速检索行并进行一些非常慢的客户端处理,您可能能够将初始检索时间缩短到 30 秒以下,但我对此表示怀疑。 )

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

        【讨论】:

          【解决方案7】:

          这是一个 UGLY hack,但可能有助于暂时解决您的问题,直到您可以解决真正的问题

              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++;
                      }
                  }
              }
          

          【讨论】:

            【解决方案8】:
            command.CommandTimeout *= 2;
            

            这将使默认超时时间增加一倍,即 30 秒。

            或者,将 CommandTimeout 的值放在配置文件中,这样您就可以根据需要调整它而无需重新编译。

            【讨论】:

            • 我无法更改超时。这违反了这里的标准。 :(
            • 您并没有增加连接的超时时间,但是......您只是增加了命令的超时时间。换句话说,一旦命令的生命周期结束,增加的超时长度也是如此。也许这足以让您绕过您的(在此处插入绰号)标准?
            • 好吧。在提出任何建议之前,我正在寻找解决方案。
            【解决方案9】:

            您应该将查询分成多个块,每个块在超时期限内执行。

            【讨论】:

            • 这只是一个查询。有时需要更长的时间。我正在寻找任何方法来保持连接活跃..
            • 保持连接活动的唯一方法是增加超时时间。这就是增加超时的作用......它使连接保持活动状态。
            【解决方案10】:

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

            【讨论】:

            • 这是否记录在任何地方?你真的不能增加长度,只能减少?
            • 这不是我回答问题的方式 - 用户在问如果增加超时时间他可以做什么不是一个选项。所以我通过建议他应该减少他的查询执行的时间来回答他,以保持在超时限制内。超时时间可以任意设置。
            【解决方案11】:

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

            【讨论】:

              【解决方案12】:

              您是否考虑过将查询分解成几个更小的块?

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

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

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

              干杯

              【讨论】:

                【解决方案13】:

                您是否尝试过将您的 sql 包装在一个存储过程中,它们似乎有更好的内存管理。以前在使用经典 ADO 进行内部查询的计划 sql 语句中看到过这样的超时。即 select * from (select ....) t inner join somthingTable。内部查询返回大量结果的地方。

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

                希望对你有帮助

                【讨论】:

                  【解决方案14】:

                  更新:看起来查询没有 抛出任何超时。连接是 超时。

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

                  【讨论】:

                  • 我同意。龙,您在正常命令执行期间无法获得连接超时。使用堆栈显示您的异常。
                  【解决方案15】:

                  可能值得尝试将结果分页。

                  【讨论】:

                    【解决方案16】:

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

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

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2012-11-03
                      • 2012-09-28
                      • 2012-02-23
                      • 1970-01-01
                      • 1970-01-01
                      • 2020-01-15
                      相关资源
                      最近更新 更多