ExecuteNonQuery () и УСТАНОВИТЬ NOCOUNT ON

Я использую MS SQL Server 2008 R2. У меня есть приложение C # - его клиент. Я обнаружил следующую ошибку (и все еще не могу ее воспроизвести. Следующий клиентский код приводит к «количеству затронутых строк» ​​больше, чем следовало бы:

…
DbCommand cmd = db.GetStoredProcCommand("TheStoredProc");
int numberOfAffectedRows = db.ExecuteNonQuery(cmd);
…

Сохраненная процедура TheStoredProc в БД выглядит следующим образом:

PROCEDURE TheStoredProc 
as

    declare @Var1 int

    **SET NOCOUNT ON;**
…
insert into [Workflows]
    (
        WorkflowInstanceID,
        Status
    )
    select WorkflowInstanceID, 1
        from #tmp


    DROP TABLE #tmp

Это унаследованный код; Я не являюсь его автором. Но из контекста я вижу - Клиент ожидает, что ExecuteNonQuery принесет количество строк, вставленных оператором «вставить в [рабочие процессы]…».

И только этим оператором INSERT. Процедура содержит еще один INSERT перед этим; но Клиенту необходимо заполнить numberOfAffectedRows счетчиком только строк, вставленных с помощью «вставки в [Workflows]…».

Ошибка заключается в следующем: numberOfAffectedRows получило значение 464. Но из содержимого БД я вижу, что это должно было быть 419. И ошибка не воспроизводима - на данный момент я видел ее только один раз на сервере Productions; и все еще не могу воспроизвести его на моем тестовом сервере. На тестовом сервере числоOfAffectedRows верное.

У меня следующая версия: причина ошибки - «SET NOCOUNT ON» в начале TheStoredProc. Здесь я обнаружил ту же проблему:

… Я слышал о нескольких побочных эффектах использования "SET NOCOUNT ON" a. Функция SQLCommand.ExecuteNonQuery возвращает неправильное количество строк, если для хранимой процедуры установлено значение SET NOCOUNT ON. …

Чаще (на других форумах) я встречал жалобу на то, что в этой ситуации ExecuteNonQuery возвращает (-1).

Как вы думаете - я прав?

Исправление должно быть следующим: вставить «SET NOCOUNT OFF» прямо перед «вставить в [Workflows]…». На моем тестовом сервере это работает нормально, но исходный код работает и на тестовом сервере….


person Victor Sotnikov    schedule 16.04.2015    source источник
comment
Сложно сказать, задаете ли вы вопрос или уже имеете ответ   -  person crthompson    schedule 16.04.2015
comment
Оба :-) У меня есть ответ; но не на 100% - так как, как я уже сказал, просто не может воспроизвести ситуацию на тестовом сервере. Поэтому все, что я могу сделать, прежде чем устанавливать исправление на производственный сервер, - это спросить людей - я прав; или вы можете предложить другую версию, объясняющую произошедшее? А может вы заметили недоработку в моей версии?   -  person Victor Sotnikov    schedule 16.04.2015
comment
Я понимаю. Может быть ваша проблема в кешировании? Если вы измените sproc, это заставит сервер перекомпилировать, а затем даст вам другие результаты. Возможно, счетчик не имеет значения, и его просто нужно обновить.   -  person crthompson    schedule 16.04.2015
comment
Может быть ваша проблема в кешировании? - Встречал ситуации, когда кеширование сказывалось на производительности (сниффинг параметров). Но как это могло повлиять на сам результат - я имею в виду, когда вместо 419 возвращается число 464?   -  person Victor Sotnikov    schedule 16.04.2015
comment
Кэширование было неподходящим термином, приношу свои извинения. Скорее, ранее скомпилированный sproc против вновь скомпилированного sproc.   -  person crthompson    schedule 16.04.2015


Ответы (1)


Я бы подумал, что установка SET NOCOUNT ON всегда будет возвращать -1 (могут быть случаи, когда это не так, но ...)

ExecuteNonQuery подсчитывает количество строк, затронутых вставкой / обновлением, а также любые строки, измененные из-за триггеров. Есть ли у вас какие-либо триггеры для затронутых таблиц в тестовой или производственной базе данных, которые могут вести себя по-другому?

Есть ли причина, по которой вы не хотели бы явно возвращать количество строк, которые вас интересуют? Например, измените и добавьте это после интересующей вас вставки:

select @rowcount = @@ROWCOUNT

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

person Chris Steele    schedule 16.04.2015
comment
(могут быть случаи, когда это не так, но ...) не могли бы вы немного рассказать об этом? - person Endrju; 03.07.2015