SqlCommand.Cancel() вызывает повышение производительности?

Я видел, как это показывало несколько мест в коде, никогда с объяснением, просто критический комментарий над ним (декларация и исполнение включены для идеи контекста. Это просто стандартная процедура запуска SqlCommand):

//SqlCommand cmd = new SqlCommand();
//cmd.ExecuteReader();
//Read off the results

//Cancel the command. This improves query time.
cmd.Cancel ();

В принципе, после завершения запроса он возвращается и отменяет его, требуя некоторого повышения производительности. Я предполагаю, что вы можете получить некоторую память обратно, когда она идет, и освобождает XmlReader, но обычно она собирается выйти из области в любом случае.

Я никогда не беспокоился об этом раньше, но он, наконец, появился в коде, который я просматриваю. Отменяет ли SqlCommand после запуска его в коде на самом деле как-то ускоряет его, или это просто какое-то странное предсказание программиста?

Ответ 1

Согласно MSDN, это правильно.

Метод Close заполняет значения для выходных параметров, возвращаемых значений и RecordsAffected, увеличивая времени, которое требуется, чтобы закрыть SqlDataReader, который использовался для обработки большой или сложный запрос. Когда возвращаемые значения и количество записи, затронутые запросом, не являются существенное, время, которое требуется для закрыть SqlDataReader можно будет уменьшить путем вызова метода Отмена связанный объект SqlCommand перед вызывая метод Close.

Weird!

Ответ 2

Вызов Cancel дает потенциально МАССИВНОЕ повышение производительности, если ваш вызов ExecuteReader возвращает большое количество строк, и вы не читаете все строки.

Чтобы проиллюстрировать, скажем, запрос возвращает миллион строк, и вы закрываете читатель после прочтения только первых 1000 строк. Если вы не вызываете Cancel перед закрытием считывателя, метод Close будет блокировать, пока он внутренне перечисляет оставшиеся 999 000 строк

Попробуйте и посмотрите!

Ответ 3

Наша техническая команда в Cinchcast провела некоторый бенчмаркинг, и мы обнаружили, что добавление cmd.Cancel() фактически замедляет его.

У нас есть вызов DALC, который получает список эпизодов для хоста. Мы запускали его 1000 раз и получали среднее время отклика, чтобы вернуть 10 эпизодов.

Итак, возвращая 10 шоу Средний с отменой: 0.069s Среднее Без Отмена: 0.026s

Довольно значительно медленнее при работе с возвращением 10 эпизодов.

Итак, я попытался снова с возвращением 100 эпизодов, чтобы увидеть, делает ли больший набор результатов значение.

Итак, возвращая 100 шоу по каждому звонку Средний с отменой: 0.132s Среднее Без Отмена: 0.122s

На этот раз разница во времени была намного меньше. Это еще быстрее, но без использования Отмена для обычных случаев использования.

Ответ 4

В вашем примере вы открываете читатель, читаете все строки и команду Отменить, но вы не показывали, где читатель закрывается.

Убедитесь, что отмена выполняется до Dispose/Close. Например, вы не получили бы повышение производительности в этом примере (настоящий код в производстве, к сожалению):

using (var rdr = cmd.ExecuteReader (CommandBehavior.Default))
{
   retval = DocumentDir.DBRead (rdr);
}

// Optimization.  Allows reader to close more quickly.... NOT!
cmd.Cancel ();  // bad!

Слишком плохо, что он уже закрыт с помощью инструкции!

Вот как следует читать, чтобы понять потенциальную выгоду:

using (var rdr = cmd.ExecuteReader (CommandBehavior.Default))
{
   retval = DocumentDir.DBRead (rdr);

   // Optimization.  Allows reader to close more quickly.
   cmd.Cancel ();
}

От MSDN SqlCommand.Cancel:

В некоторых редких случаях, если вы вызываете ExecuteReader, тогда вызывайте Close (неявно или явно) перед вызовом Отмена, а затем вызывайте Отмена, команда cancel не будет отправлена ​​на SQL Server, а набор результатов может продолжить для потока после вызова Close. Чтобы этого избежать, убедитесь, что вы вызываете "Отмена" перед закрытием устройства чтения или подключения.