Что делает SQL Server с запросом на рассылку?

Предположим, что я использую С# для запуска длительной хранимой процедуры SQL Server (скажем, 30 минут). Предположим далее, что я задал 1-часовой период таймаута для запроса в С# таким образом, что если по какой-либо причине этот SP занимает больше времени, чем ожидалось, я не стану монополизировать БД. Наконец, предположим, что эта хранимая процедура имеет в ней блок try/catch, чтобы улавливать ошибки и выполнять некоторую очистку, если какие-либо шаги внутри нее терпят неудачу.

Некоторый код (С#):

using (SqlCommand comm = new SqlCommand("longrunningstoredproc"))
{
    comm.Connection = conn;
    comm.CommandType = CommandType.StoredProcedure;
    comm.CommandTimeout = 3600;
    comm.ExecuteNonQuery();
}
/* Note: no transaction is used here, the transactions are inside the stored proc itself. */

T-SQL (в основном, соответствует следующему):

BEGIN TRY
   -- initiailize by inserting some rows into a working table somewhere
   BEGIN TRANS
     -- do long running work
   COMMIT TRANS
   BEGIN TRANS
     -- do long running work
   COMMIT TRANS
   BEGIN TRANS
     -- do long running work
   COMMIT TRANS
   BEGIN TRANS
     -- do long running work
   COMMIT TRANS
   BEGIN TRANS
     -- do long running work
   COMMIT TRANS
   -- etc.

   -- remove the rows from the working table (and set another data point to success)
END TRY
BEGIN CATCH
   -- remove the rows from the working table (but don't set the other data point to success)
END CATCH

Мой вопрос: что SQL Server сделает с запросом, когда команда выйдет со стороны С#? Будет ли он ссылаться на блок catch SP, или он просто полностью отключит его, так что мне нужно будет выполнить очистку кода С#?

Ответ 1

Тайм-аут применяется ADO.NET. SQL Server не знает такой вещи, как тайм-аут команды. Клиент .NET отправит команду TDS "внимание". Вы можете наблюдать это поведение с помощью SQL Profiler, потому что оно имеет событие "внимания".

Когда SQL Server получает отмену, он отменяет текущий выполняемый запрос (точно так же, как SSMS делает, когда вы нажимаете кнопку остановки). Он отменяет пакет (как в SSMS). Это означает, что код catch не может выполняться. Соединение останется в живых.

По моему опыту транзакция будет немедленно отброшена. Я не думаю, что это гарантировано.

TL; DR: Тайм-аут в ADO.NET ведет себя так же, как если бы вы нажали кнопку остановки в SSMS (или называли SqlCommand.Cancel).

Вот ссылка для этого: http://blogs.msdn.com/b/psssql/archive/2008/07/23/how-it-works-attention-attention-or-should-i-say-cancel-the-query-and-be-sure-to-process-your-results.aspx

Ответ 2

Тайм-аут - это то, что происходит в соединении, а не выполняемый запрос.

Это означает, что ваш BEGIN CATCH не будет выполняться в случае таймаута, так как запрос не знает об этом.

Напишите свою очистку на С# в блоке catch(SqlException ex) (тестирование на время ожидания).