Устранение ошибок времени ожидания запроса

Симптомы

Предположим, что приложение запрашивает данные из базы данных SQL Server. Если запрос не возвращает данные в течение заданного значения времени ожидания (обычно 30 секунд), приложение отменяет запрос и создает одно из следующих сообщений об ошибке:

  • Истекло время ожидания. Срок ожидания истек до завершения операции, или сервер не отвечает. Выполнение инструкции прекращено.

  • System.Data.SqlClient.SqlException: истекло время ожидания. Срок ожидания истек до завершения операции, или сервер не отвечает.

Объяснение

Эти ошибки возникают на стороне приложения. Приложение задает значение времени ожидания, и по его истечении оно отменяет запрос. На стороне SQL Server отмена запроса со стороны клиента вызывает событие «Внимание», ошибку 3617 (MSSQLSERVER_3617). Если время ожидания на стороне приложения равно 0 (без ограничения по времени), ядро СУБД выполняет запрос до его завершения.

  • В платформе .NET Framework System.Data.SqlClient значение времени ожидания задается в свойстве CommandTimeout.
  • В API ODBC значение времени ожидания задается с помощью атрибута SQL_ATTR_QUERY_TIMEOUT в функции SQLSetStmtAttr.
  • В API Java Database Connectivity (JDBC) значение времени ожидания задается с помощью метода setQueryTimeout.
  • В OLEDB значение времени ожидания задается через свойство DBPROP_COMMANDTIMEOUT структуры DBPROP.
  • В VBA (Excel) значение времени ожидания задается через свойство ADODB.Command.CommandTimeout.

Время ожидания запроса отличается от свойства времени ожидания подключения. Последнее определяет время ожидания успешного подключения и не участвует в выполнении запроса. Дополнительные сведения см. в разделе Время ожидания запроса не совпадает с временем ожидания подключения.

Действия по устранению неполадок

На данный момент наиболее распространенной причиной времени ожидания запросов являются неэффективные запросы. Это означает, что запрос выполняется дольше, чем предопределенное значение времени ожидания запроса. Ускорение выполнения запроса является рекомендуемой первой целью устранения неполадок. Вот как проверить запросы:

  1. Используйте расширенные события или трассировку SQL для определения запросов, которые вызывают ошибки времени ожидания. Вы можете отслеживать событие Внимание вместе с sql_batch_completed и расширенными событиями rpc_completed и сопоставлять их с одним и тем же session_id. Если вы заметили, что за завершенным событием сразу последует событие внимания, а длительность завершенного события примерно соответствует параметру времени ожидания, то запрос определен. Пример:

    Примечание.

    В этом примере запрос SELECT выполнялся почти ровно 30 секунд и был остановлен. Событие «Внимание» с одинаковым идентификатором сеанса указывает, что запрос был отменен приложением.

    Имя Session_id Sql_text Длительность (в микросекундах) Timestamp
    sql_batch_started 54 Выберите … от клиентов, ГДЕ cid = 192937 NULL 2021-09-30 09:50:25.0000
    sql_batch_completed 54 Выберите … от клиентов, ГДЕ cid = 192937 29999981 2021-09-30 09:50:55.0000
    Внимание 54 Выберите … от клиентов, ГДЕ 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, но медленно на стороне приложения, измените запросы, чтобы использовать те же параметры SET, которые используются в SQLCMD и SSMS. Сравните параметры SET, собрав трассировку расширенных событий (вход и подключение событий collect_options_text), и проверьте столбец 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);
                    }
                }
            }
        }
    }
    

Время ожидания запроса не совпадает с временем ожидания подключения

Время ожидания запроса отличается от времени ожидания подключения или времени ожидания входа. Превышение времени ожидания подключения или входа возникает в том случае, если начальное подключение к серверу базы данных достигает предопределенного времени ожидания. На этом этапе запрос не был отправлен на сервер. Эти сообщения являются примерами ошибки времени ожидания подключения или входа:

  • Истекло время ожидания соединения. Время ожидания истекло при попытке обработки подтверждения предварительного согласования. Возможно, произошел сбой во время предварительного согласования, или сервер не смог ответить вовремя. Время, затраченное на попытки подключиться к этому серверу, составило: [Pre-Login] initialization=23; handshake=14979;

  • Истекло время ожидания. Срок ожидания истек до завершения операции, или сервер не отвечает. System.ComponentModel.Win32Exception (0x80004005): Время ожидания операции истекло.

Значение времени ожидания подключения является параметром на стороне клиента и обычно равно 15 секундам. Дополнительные сведения об устранении неполадок со временем ожидания подключения см. в разделе Устранение неполадок со временем ожидания подключения. Сведения об устранении неполадок со временем ожидания запросов см. в этом видеоролике.