排查查询超时错误

症状

假设应用程序从 SQL Server 数据库查询数据。 如果查询在配置的超时值(通常 30 秒内)不返回任何数据,则应用程序将取消查询并生成以下错误消息之一:

  • 超时过期。 The timeout period elapsed prior to completion of the operation or the server is not responding. 该语句已终止。

  • System.Data.SqlClient.SqlException:超时过期 The timeout period elapsed prior to completion of the operation or the server is not responding.

说明

这些错误发生在应用程序端。 应用程序设置超时值,如果超时将取消查询。 在 SQL Server 端,客户端的查询取消会导致注意事件,错误 3617 (MSSQLSERVER_3617) 。 如果应用程序端的超时值设置为 0 (没有时间限制) ,则数据库引擎将执行查询,直到查询完成。

  • 在 .NET Framework System.Data.SqlClient 中,超时值在 CommandTimeout 属性上设置。
  • 在 ODBC API 中,它通过 SQLSetStmtAttr 函数中的 SQL_ATTR_QUERY_TIMEOUT 属性进行设置。
  • 在 Java 数据库连接 (JDBC) API 中,它通过 setQueryTimeout 方法进行设置。
  • 在 OLEDB 中,它通过 DBPROP 结构上的 DBPROP_COMMANDTIMEOUT 属性进行设置。
  • 在 VBA (Excel) 中,它通过 ADODB.Command.CommandTimeout 属性进行设置。

查询超时与连接超时属性不同。 后者控制等待成功连接的时间,而不参与查询执行。 有关详细信息,请参阅查询超时与连接超时不同

故障排除步骤

到目前为止,查询超时的最常见原因是查询表现不佳。 这意味着查询的运行时间超过预定义的查询超时值。 提高查询的运行速度是推荐排查的首要目标。 以下是检查查询的方法:

  1. 使用“扩展事件”或“SQL 跟踪”来识别导致超时错误的查询。 可以将关注事件与 sql_batch_completed 事件和 rpc_completed 扩展事件一起跟踪,并将其关联在同一个 session_id 上。 如果观察到已完成事件后紧跟一个注意事件,并且已完成事件的持续时间大致对应于超时设置,则你已确定查询。 下面是一个示例:

    注意

    在该示例中,SELECT 查询几乎正好运行了 30 秒然后停止。 具有相同会话 ID 的注意事件表示应用程序已取消查询。

    名称 Session_id Sql_text 持续时间(微秒) Timestamp
    sql_batch_started 54 选择 … from Customers WHERE cid = 192937 NULL 2021-09-30 09:50:25.0000
    sql_batch_completed 54 选择 … from Customers WHERE cid = 192937 29999981 2021-09-30 09:50:55.0000
    注意 54 选择 … from Customers WHERE cid = 192937 40000 2021-09-30 09:50:55.0400
  2. 在 SQLCMD 或 SQL Server Management Studio (SSMS) 中执行和测试查询。

  3. 如果 SQLCMD 和 SSMS 中的查询速度也较慢,请对查询进行疑难解答并提高性能。 有关详细信息,请参阅排查SQL Server中运行缓慢的查询问题

    注意

    在 SQLCMD 和 SSMS 中,超时值设置为 0(无时间限制)并且可以测试和调查查询。

  4. 如果在 SQLCMD 和 SSMS 中的查询速度很快,但在应用程序端速度缓慢,请更改查询以使用 SQLCMD 和 SSMS 中使用的相同 SET 选项。 通过收集扩展事件跟踪(使用 collect_options_text 登录和连接事件)比较 SET 选项并查看 options_text 列。 下面是一个示例:

    ALTER EVENT SESSION [setOptions] ON SERVER 
    ADD EVENT sqlserver.existing_connection(SET collect_options_text=(1) 
        ACTION(package0.event_sequence,package0.last_error,sqlos.system_thread_id,sqlserver.context_info,sqlserver.session_id,sqlserver.sql_text)), 
    ADD EVENT sqlserver.login(SET collect_options_text=(1)
        ACTION(sqlos.system_thread_id,sqlserver.context_info,sqlserver.sql_text))
    

    有关详细信息,请参阅 对数据库应用程序和 SSMS 之间的查询性能差异进行疑难解答

  5. 检查 CommandTimeout 设置是否小于预期的查询持续时间。 如果用户的设置正确但仍然出现超时,则是因为查询性能问题。 下面是一个 ADO.NET 代码示例,超时值设置为 10 秒:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Data.SqlClient;
    using System.Data;
    
    namespace ConsoleApplication6
    {
        class Program
        {
            static void Main()
            {
                string ConnectionString = "Data Source=.\sql2019;Integrated Security=SSPI;Initial Catalog=tempdb;";
                string queryString = "exec test";
    
                using (SqlConnection connection = new SqlConnection(ConnectionString))
                {
                    connection.Open();
                    SqlCommand command = new SqlCommand(queryString, connection);
    
                    // Setting command timeout to 10 seconds
                    command.CommandTimeout = 10;
                    //command.ExecuteNonQuery();
                    try {
                        command.ExecuteNonQuery();
                    }
                    catch (SqlException e) {
                        Console.WriteLine("Got expected SqlException due to command timeout ");
                        Console.WriteLine(e);
                    }
                }
            }
        }
    }
    

查询超时与连接超时不同

查询超时不同于连接超时或登录超时。当与数据库服务器的初始连接达到预定义的超时时间段时,会出现连接或登录超时。 在此阶段,尚未向服务器提交任何查询。 这些消息是连接或登录超时错误的示例:

  • 连接超时时间已到。 在尝试使用登录前握手确认时超过了此超时时间。 这可能是因为登录前握手失败或服务器无法及时响应。 尝试连接到此服务器所花费的持续时间为 [登录前] 初始化 = 23; 握手=14979;

  • 超时过期。 The timeout period elapsed prior to completion of the operation or the server is not responding. System.ComponentModel.Win32Exception (0x80004005):等待操作超时。

连接超时值是客户端设置,通常设置为 15 秒。 有关如何对连接超时问题进行疑难解答的详细信息,请参阅连接超时疑难解答。 有关查询超时疑难解答,请观看此视频