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

发布于 2024-07-06 19:13:14 字数 578 浏览 4 评论 0原文

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

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

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

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

This is a sample code for executing a query. Sometimes, while executing time consuming queries, it throws a timeout exception.

I cannot use any of these techniques:
1) Increase timeout.
2) Run it asynchronously with a callback. This needs to run in a synchronous manner.

please suggest any other techinques to keep the connection alive while executing a time consuming query?

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();
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

寻找我们的幸福 2024-07-13 19:13:14

由于您使用的 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));

Since you are using ExecuteNonQuery which does not return any rows, you can try this polling based approach. It executes the query in an asyc manner (without callback)
but the application will wait (inside a while loop) until the query is complete. From MSDN. This should solve the timeout problem. Please try it out.

But, I agree with others that you should think more about optimizing the query to perform under 30 seconds.

        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));
烛影斜 2024-07-13 19:13:14

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

You should first check your query to see if it's optimized and it isn't somehow running on missing indexes. 30 seconds is allot for most queries, even on large databases if they are properly tuned. If you have solid proof using the query plan that the query can't be executed any faster than that, then you should increase the timeout, there's no other way to keep the connection, that's the purpose of the timeout to terminate the connection if the query doesn't complete in that time frame.

妄司 2024-07-13 19:13:14

我必须同意Terrapin的观点。

您有几种选择来减少时间。 首先,如果您的公司雇用了 DBA,我建议您向他们寻求建议。

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

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

I have to agree with Terrapin.

You have a few options on how to get your time down. First, if your company employs DBAs, I'd recommend asking them for suggestions.

If that's not an option, or if you want to try some other things first here are your three major options:

  1. Break up the query into components that run under the timeout. This is probably the easiest.
  2. Change the query to optimize the access path through the database (generally: hitting an index as closely as you can)
  3. Change or add indices to affect your query's access path.
放手` 2024-07-13 19:13:14

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

  1. 与您的 DBA 和另一位代码审查人员一起验证您是否真正尽可能地优化了查询
  2. 在底层数据库结构上进行工作,看看您是否可以在数据库方面获得任何收益,创建/修改索引。
  3. 将其分为多个部分,即使这意味着运行具有多个返回参数的过程,这些返回参数只是调用另一个参数。 (这个选项并不优雅,老实说,如果您的代码真的要花费这么多时间,我将进行管理并重新讨论 30 秒超时)

If you are constrained from using the default process of changing the timeout value you will most likely have to do a lot more work. The following options come to mind

  1. Validate with your DBA's and another code review that you have truly optimized the query as best as possible
  2. Work on the underlying DB structure to see if there is any gain you can get on the DB side, creating/modifying an idex(es).
  3. Divide it into multiple parts, even if this means running procedures with multiple return parameters that simply call another param. (This option is not elegant, and honestly if your code REALLY is going to take this much time I would be going to management and re-discussing the 30 second timeout)
旧夏天 2024-07-13 19:13:14

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

在查询期间,在数据库服务器上的主数据库上运行此查询,并查看是否存在需要排除故障的锁:

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

We recently had a similar issue on a SQL Server 2000 database.

During your query, run this query on your master database on the db server and see if there are any locks you should troubleshoot:

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 also contains a very cool activity monitor which lets you see the health of your database during your query.

In our case, it was a networkio lock which kept the database busy. It was some legacy VB code which didn't disconnect its result set quick enough.

挽心 2024-07-13 19:13:14

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

与优化 SQL 的收益相比,通过优化 ADO.NET 的使用获得的性能收益很小。

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

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

If you are prohibited from using the features of the data access API to allow a query to last more than 30 seconds, then we need to see the SQL.

The performance gains to be made by optimizing the use of ADO.NET are slight in comparison to the gains of optimizing the SQL.

And you already are using the most efficient method of executing SQL. Other techniques would be mind numbingly slower (although, if you did a quick retrieval of your rows and some really slow client side processing using DataSets, you might be able to get the initial retrieval down to less than 30 seconds, but I doubt it.)

If we knew if you were doing inserts, then maybe you should be using bulk insert. But we don't know the content of your sql.

美人骨 2024-07-13 19:13:14

这是一个丑陋的黑客,但可能会暂时帮助您解决问题,直到您解决真正的问题

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

This is an UGLY hack, but might help solve your problem temporarily until you can fix the real problem

    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++;
            }
        }
    }
私野 2024-07-13 19:13:14
command.CommandTimeout *= 2;

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

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

command.CommandTimeout *= 2;

That will double the default time-out, which is 30 seconds.

Or, put the value for CommandTimeout in a configuration file, so you can adjust it as needed without recompiling.

无力看清 2024-07-13 19:13:14

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

You should break your query up into multiple chunks that each execute within the timeout period.

梦初启 2024-07-13 19:13:14

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

If you absolutely cannot increase the timeout, your only option is to reduce the time of the query to execute within the default 30 second timeout.

御弟哥哥 2024-07-13 19:13:14

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

I tend to dislike increasing the connection/command timeout since in my mind that would be a matter of taking care of the symptom, not the problem

初熏 2024-07-13 19:13:14

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

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

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

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

干杯

have you thought about breaking the query down into several smaller chunks?

Also, have you ran your query against the Database Engine Tuning Advisor in:

Management Studio > Tools > Database Engine Tuning Advisor

Lastly, could we get a look at the query itself?

cheers

我的奇迹 2024-07-13 19:13:14

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

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

希望这可以帮助

Have you tried wrapping your sql inside a stored procedure, they seem to have better memory management. Have seen timeouts like this before in plan sql statement with internal queries using classic ADO. i.e. select * from (select ....) t inner join somthingTable. Where the internal query was returning a very large number of results.

Other tips
1. Performing reads with the with(nolock) execution hint, it's dirty and I don't recommend it but it will tend to be faster.
2. Also look at the execution plan of the sql your trying to run and reduce the row scanning, the order in which you join tables.
3. look at adding some indexes to your tables for faster reads.
4. I've also found that deleting rows is very expensive, you could try and limit the number of rows per call.
5. Swap @table variables with #temporary tables has also worked for me in the past.
6. You may also have saved bad execution plan (heard, never seen).

Hope this helps

药祭#氼 2024-07-13 19:13:14

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

哎呀,即使不执行查询,连接也会超时? 因为有两个超时:连接超时和查询超时。 每个人似乎都关注查询,但如果出现连接超时,则这是一个网络问题,与查询无关:显然,必须先建立连接,然后才能运行查询。

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

I.o.w., even if you don't execute a query, the connection times out? because there are two time-outs: connection and query. Everybody seems to focus on the query, but if you get connection timeouts, it's a network problem and has nothing to do with the query: the connection first has to be established before a query can be ran, obviously.

惜醉颜 2024-07-13 19:13:14

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

It might be worth trying paging the results back.

恋你朝朝暮暮 2024-07-13 19:13:14

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

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

just set sqlcommand's CommandTimeout property to 0, this will cause the command to wait until the query finishes...
eg:

SqlCommand cmd = new SqlCommand(spName,conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 0;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文