Какое значение статистики соответствует ADO.net SqlCommand.Свойство CommandTimeout?

#c# #sql-server #ado.net

#c# #sql-сервер #ado.net

Вопрос:

Я пытаюсь понять это свойство, у меня есть функция для запуска sql-запроса в ADO.net где я установил SqlCommand.Подключите свойство Timeout к 500 секундам и SqlCommand.Свойство CommandTimeout на 1 секунду. Примерно соответствующая часть выглядит так.

         var conn = dbConn as SqlConnection;
        conn.ConnectTimeout = 500;
        conn.StatisticsEnabled = true;

        try
        {
            using (var command = new SqlCommand(query, conn))
            {
                command.CommandTimeout = 1;
                using (var adapter = new SqlDataAdapter(command))
                {
                    var rowsCount = adapter.Fill(startIdx, MaxRows, new DataTable[] { dtResult });
                    var stats = conn.RetrieveStatistics();
                    long commandExecutionTimeInMs = (long)stats["ExecutionTime"];
                    long commandNetworkServerTimeInMs = (long)stats["NetworkServerTime"];
                    Console.Writeline("Command statistics execution time: "   commandExecutionTimeInMs.ToString());
                    Console.Writeline("Command statistics network server time: "   commandNetworkServerTimeInMs.ToString());
                    conn.ResetStatistics();
                    conn.StatisticsEnabled = false;
                    return rowsCount;
                }
            }
        }
        catch (Exception ex)
        {
            var stats = conn.RetrieveStatistics();
            long commandExecutionTimeInMs = (long)stats["ExecutionTime"];
            long commandNetworkServerTimeInMs = (long)stats["NetworkServerTime"];
            Console.Writeline("Command statistics execution time: "   commandExecutionTimeInMs.ToString());
            Console.Writeline("Command statistics network server time: "   commandNetworkServerTimeInMs.ToString());
            conn.ResetStatistics();
            conn.StatisticsEnabled = false;
        } 
  

При этом я ожидаю, что любое время выполнения, превышающее 1 секунду, истечет и выдаст исключение с этим сообщением: «Время ожидания выполнения истекло. Период ожидания, прошедший до завершения операции, или сервер не отвечает.». Однако это очень непоследовательно, мои журналы показывают мне, что время выполнения может достигать нескольких секунд или даже 10 секунд, иногда ничего не выбрасывая. А время сетевого сервера постоянно находится в диапазоне от 200 до 300 мс.

Так в чем же здесь проблема? Я неправильно понимаю, как работает CommandTimeout? Я смотрю на неправильное значение статистики? Я хочу установить значение CommandTimeout равным 1, а затем, когда мой запрос превысит это время, я смогу четко увидеть статистику, которая регистрирует время как 1 с или 1000 мс в блоке catch

Ссылка на эту страницу, похоже, больше ничего не имеет значения https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/sql/provider-statistics-for-sql-server

Комментарии:

1. Ваше соединение принадлежит блоку using. Соединения используют неуправляемые ресурсы, которые освобождаются в их методе .Dispose. Для соединений необходимо вызвать их метод dispose. С этим справится блок using.

2. Спасибо за подсказку, на самом деле это всего лишь фрагмент функции, в которую передается соединение, просто чтобы проиллюстрировать проблему, само соединение впоследствии обрабатывается должным образом.

Ответ №1:

В документах есть примечания и 2 примечания.

Замечание

 !Note

The CommandTimeout property will be ignored by older APM (Asynchronous Programming Model) asynchronous method calls such as BeginExecuteReader. It will be honored by newer TAP (Task Asynchronous Programming) methods such as ExecuteReaderAsync.

!Note

This property is the cumulative time-out (for all network packets that are read during the invocation of a method) for all network reads during command execution or processing of the results. A time-out can still occur after the first row is returned, and does not include user processing time, only network read time.

For example, with a 30 second time out, if Read requires two network packets, then it has 30 seconds to read both network packets. If you call Read again, it will have another 30 seconds to read any data that it requires.
  

Комментарии:

1. Я просмотрел документы раньше, и на самом деле это не тот ответ, который я ищу. Хотя это побудило меня поискать обсуждение вокруг SqlDataAdapter, которое приведет к окончательному ответу, который я опубликую отдельно.

Ответ №2:

После изучения документации и обсуждений методов, которые я использовал, я думаю, что нашел ответ. Похоже, что это не новая проблема для людей, использующих SqlDataAdapter. Цитирую инженера Microsoft здесь:

SqlCommand.Свойство CommandTimeout влияет только на одну операцию команды. Таким образом, установленное время ожидания будет равняться общему времени для всех сетевых операций чтения во время одного выполнения, такого как SqlCommand.ExecuteReader или SqlDataReader.Read(), SqlDataReader.getString(). Время ожидания сбрасывается при каждом вызове новой операции.

SqlDataAdapter использует общедоступный интерфейс команды, поэтому он вызывает ExecuteReader один раз, за которым следует вызов нескольких операций DataReader по мере необходимости для извлечения данных. Таким образом, общее время составляет (один вызов для ExecuteReader другие операции по команде) X CommandTimeout, в зависимости от параметров.

Ссылка: https://social.msdn.microsoft.com/Forums/en-US/de557eb1-aa0f-403d-89c6-199bb318a08f/sqldataadapterfill-does-not-time-out-when-it-should?форум=adodotnetdataproviders

SqlDataAdapter.Метод Fill(), который я использую, вероятно, выполняет несколько операций, поэтому он легко превышает время ожидания с точки зрения времени выполнения, но фактически не вызывает исключение.