УСТАНОВИТЬ НАКОПЛЕНИЕ ON

Вдохновленный этот вопрос, где есть разные взгляды на SET NOCOUNT...

Должны ли мы использовать SET NOCOUNT ON для SQL Server? Если нет, почему бы и нет?

Что он делает Редактировать 6, 22 июля 2011 г.

Он подавляет сообщение "xx rows affected" после любого DML. Это набор результатов, и при отправке клиент должен его обработать. Он крошечный, но измеримый (см. Ответы ниже)

Для триггеров и т.д. клиент получит несколько "xx rows affected", и это вызывает всевозможные ошибки для некоторых ORM, MS Access, JPA и т.д. (см. правки ниже)

Фон:

Общепринятая лучшая практика (я думал до этого вопроса) заключается в использовании SET NOCOUNT ON в триггерах и хранимых процедурах в SQL Server. Мы используем его повсеместно, и быстрый Google показывает, что большое количество MVP-клиентов SQL Server тоже соглашаются.

MSDN говорит, что это может сломать .NET SQLDataAdapter.

Теперь это означает, что SQLDataAdapter ограничен исключительно обработкой CRUD, потому что он ожидает, что сообщение "n rows affected" будет соответствовать. Поэтому я не могу использовать:

  • IF EXISTS, чтобы избежать дублирования (нет сообщений, затрагивающих строки) Примечание: используйте с осторожностью
  • ГДЕ НЕ СУЩЕСТВУЕТ (меньше ожидаемых строк
  • Отфильтруйте тривиальные обновления (например, данные фактически не изменяются)
  • Предоставляет ли какой-либо доступ к таблице до (например, ведение журнала)
  • Скрыть сложность или denormlisation
  • и т.д.

В вопросе marc_s (кто знает свой SQL-материал) говорит, что не используйте его. Это отличается от того, что я думаю (и я считаю себя достаточно компетентным в SQL тоже).

Возможно, что я что-то упустил (не стесняйтесь указать на очевидное), но что вы думаете, думают ли вы?

Примечание: прошло много лет с тех пор, как я увидел эту ошибку, потому что сейчас я не использую SQLDataAdapter.

Редактирование после комментариев и вопросов:

Изменить: Больше мыслей...

У нас есть несколько клиентов: можно использовать С# SQLDataAdaptor, другой может использовать nHibernate из Java. Они могут быть затронуты по-разному с помощью SET NOCOUNT ON.

Если вы считаете хранимые procs как методы, то плохая форма (анти-шаблон) для принятия некоторой внутренней обработки работает определенным образом для ваших собственных целей.

Изменить 2: a триггер, разбивающий вопрос nHibernate, где SET NOCOUNT ON не может быть установлен

(и нет, это не дубликат этого)

Редактировать 3: Еще больше информации, благодаря моему коллеге MVP

Редактировать 4: 13 мая 2011 г.

Перерывы Linq 2 SQL тоже не заданы?

Редактировать 5: 14 июня 2011 г.

Разрывает JPA, хранит proc с переменными таблицы: Поддерживает ли JPA 2.0 переменные таблицы SQL Server?

Редактировать 6: 15 августа 2011

В сетке данных SSMS "Редактировать строки" требуется SET NOCOUNT ON: Обновить триггер с GROUP BY

Редактировать 7: 07 Март 2013 г.

Подробнее о деталях от @RemusRusanu:
Действительно ли SET NOCOUNT ON делает большую часть разницы в производительности.

Ответы

Ответ 1

Хорошо, теперь я сделал свое исследование, вот сделка:

В протоколе TDS SET NOCOUNT ON сохраняет только 9 байтов на запрос, а текст "SET NOCOUNT ON" сам по себе является колоссальным 14 байтами. Раньше я думал, что 123 row(s) affected были возвращены с сервера в виде обычного текста в отдельном сетевом пакете, но это не так. На самом деле это небольшая структура, называемая DONE_IN_PROC встроенная в ответ. Это не отдельный сетевой пакет, поэтому никакие обратные трассы не теряются.

Я думаю, что вы можете придерживаться поведения подсчета по умолчанию почти всегда, не беспокоясь о производительности. Однако есть некоторые случаи, когда вычисление количества строк заблаговременно повлияло бы на производительность, например, на указатель только вперед. В этом случае может потребоваться NOCOUNT. Помимо этого, абсолютно нет необходимости следовать "использованию NOCOUNT, где это возможно".

Вот подробный анализ незначительности установки SET NOCOUNT: http://daleburnett.com/2014/01/everything-ever-wanted-know-set-nocount/

Ответ 2

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

  • Если ваша хранимая процедура использует курсор для выполнения очень быстрых операций без возвращенных результатов, то при NOCOUNT OFF может быть примерно в 10 раз больше, чем при включении. 1 Это наихудший сценарий.
  • Если ваша хранимая процедура выполняет только одну быструю операцию без возвратных результатов, установка NOCOUNT ON приведет к повышению производительности на 3%. 2 Это будет соответствовать обычной процедуре вставки или обновления.
  • Если ваша хранимая процедура возвращает результаты (т.е. вы выбрали что-то), разница в производительности будет уменьшаться пропорционально размеру набора результатов.

Ответ 3

  • Когда SET NOCOUNT включен, подсчет (с указанием количества строк, на которые влияет оператор Transact-SQL) не возвращается. Когда SET NOCOUNT выключен, счетчик возвращается. Он используется с любыми операциями SELECT, INSERT, UPDATE, DELETE.

  • Настройка SET NOCOUNT устанавливается в момент выполнения или запуска, а не во время разбора.

  • SET NOCOUNT ON улучшает производительность хранимой процедуры (SP).

  • Синтаксис: SET NOCOUNT {ON | ВЫКЛ}

Пример SET NOCOUNT ON:

enter image description here

Пример SET NOCOUNT OFF:

enter image description here

Ответ 4

Я до некоторой степени догадываюсь, что это проблема с администратором и разработчиком.

Как правило, я бы сказал, что не используйте его, если вам абсолютно не нужно - потому что его использование может привести к повреждению вашего кода ADO.NET(как это описано в Microsoft).

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

Кроме того, если ваши разработчики когда-либо использовали "RecordsAffected", возвращаемый вызовом метода ADO.NET ExecuteNonQuery, у вас возникают проблемы, если каждый использует SET NOCOUNT ON, так как в этом случае ExecuteNonQuery всегда будет возвращать 0.

Также см. Peter Bromberg сообщение в блоге и проверьте его позицию.

Таким образом, это действительно сводится к тому, кто хочет установить стандарты:-)

Марк

Ответ 5

Если вы говорите, что у вас могут быть и другие клиенты, есть проблемы с классическим ADO, если SET NOCOUNT не установлен.

Один из них, который я регулярно испытываю: если хранимая процедура выполняет несколько операторов (и, следовательно, возвращается количество сообщений "xxx rows" ), ADO, похоже, не справляется с этим и выдает ошибку "Невозможно изменить свойство ActiveConnection объект Recordset, который имеет объект Command в качестве источника.

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

Ответ 6

Если вы рискуете усложнить ситуацию, я рекомендую немного другое правило всем тем, кого я вижу выше:

  • Всегда устанавливайте NOCOUNT ON в начале proc, прежде чем выполнять какую-либо работу в proc, но также всегда SET NOCOUNT OFF снова, прежде чем возвращать любые наборы записей из сохраненного proc.

Итак, "обычно продолжайте nocount, за исключением случаев, когда вы фактически возвращаете набор результатов". Я не знаю, каким образом это может нарушить любой клиентский код, это означает, что код клиента никогда не должен знать ничего о внутренних компонентах proc, и это не особенно обременительно.

Ответ 7

Что касается триггеров, нарушающих NHibernate, у меня был этот опыт из первых рук. В принципе, когда NH делает UPDATE, он ожидает определенное количество строк. Добавив SET NOCOUNT ON к триггерам, вы получите количество строк назад к тому, что NH ожидает, тем самым устраняя проблему. Так что да, я бы определенно рекомендовал отключить его для триггеров, если вы используете NH.

Что касается использования в SP, это вопрос личных предпочтений. Я всегда делал подсчет строк, но опять же, нет никаких серьезных аргументов.

В другой заметке вам стоит подумать о том, чтобы отказаться от архитектуры на основе SP, тогда у вас даже не будет этого вопроса.

Ответ 8

SET NOCOUNT ON;

Эта строка кода используется в SQL для того, чтобы не возвращать числовые строки, затронутые при выполнении запроса. Если нам не потребуется количество затронутых строк, мы можем использовать это, так как это помогло бы сохранить использование памяти и увеличить количество выполняемых запросов.

Ответ 9

SET NOCOUNT ON; Выше кода остановит сообщение, сгенерированное процессором sql server, в окно результатов после выполнения команды DML/DDL.

Почему мы это делаем? Поскольку механизм SQL-сервера принимает некоторый ресурс, чтобы получить статус и сгенерировать сообщение, он считается перегрузкой для механизма сервера Sql. Поэтому мы устанавливаем сообщение noncount.

Ответ 10

Я хотел убедиться, что "SET NOCOUNT ON" не сохраняет ни сетевой пакет, ни передачу туда и обратно

Я использовал тест SQLServer 2017 на другом хосте (я использовал виртуальную create table ttable1 (n int); insert into ttable1 values (1),(2),(3),(4),(5),(6),(7) go) для create table ttable1 (n int); insert into ttable1 values (1),(2),(3),(4),(5),(6),(7) go create table ttable1 (n int); insert into ttable1 values (1),(2),(3),(4),(5),(6),(7) go create procedure procNoCount as begin set nocount on update ttable1 set n=10-n end create procedure procNormal as begin update ttable1 set n=10-n end Затем я отследил пакеты на порту 1433 с помощью инструмента "Wireshark": кнопка "фильтр захвата" → "порт 1433"

exec procNoCount

это ответный пакет: 0000 00 50 56 c0 00 08 00 0c 29 31 3f 75 08 00 45 00 0010 00 42 d0 ce 40 00 40 06 84 0d c0 a8 32 88 c0 a8 0020 32 01 05 99 fe a5 91 49 e5 9c be fb 85 01 50 18 0030 02 b4 e6 0e 00 00 04 01 00 1a 00 35 01 00 79 00 0040 00 00 00 fe 00 00 e0 00 00 00 00 00 00 00 00 00

exec procNormal

это ответный пакет: 0000 00 50 56 c0 00 08 00 0c 29 31 3f 75 08 00 45 00 0010 00 4f d0 ea 40 00 40 06 83 e4 c0 a8 32 88 c0 a8 0020 32 01 05 99 fe a5 91 49 e8 b1 be fb 8a 35 50 18 0030 03 02 e6 1b 00 00 04 01 00 27 00 35 01 00 ff 11 0040 00 c5 00 07 00 00 00 00 00 00 00 79 00 00 00 00 0050 fe 00 00 e0 00 00 00 00 00 00 00 00 00

В строке 40 я вижу "07", это количество затронутых строк. Он включен в ответный пакет. Нет дополнительного пакета.

Однако он имеет 13 дополнительных байтов, которые могут быть сохранены, но, вероятно, не более того, чем сокращение имен столбцов (например, "ManagingDepartment" до "MD")

Так что не вижу смысла использовать его для производительности

НО, как уже упоминалось, это может сломать ADO.NET, и я также наткнулся на проблему с использованием python: MSSQL2008 - Pyodbc - Предыдущий SQL не был запросом

Так что, наверное, хорошая привычка еще...

Ответ 11

Я не знаю, как тестировать SET NOCOUNT ON между клиентом и SQL, поэтому я проверил аналогичное поведение для другой команды SET: "УСТАНОВИТЬ УРОВЕНЬ ИЗОЛЯЦИИ УСТАНОВКИ ПРОСМОТРЕТЬ НЕПРЕРЫВНО"

Я отправил команду из моего подключения, изменив поведение SQL по умолчанию (READ COMMITTED), и он был изменен для следующих команд. Когда я изменил уровень ISOLATION внутри хранимой процедуры, он не изменил поведение соединения для следующей команды.

Текущее заключение,

  • Изменение настроек внутри хранимой процедуры не изменяет настройки подключения по умолчанию.
  • Изменение настроек путем отправки команд с использованием ADOCOnnection изменяет поведение по умолчанию.

Я думаю, что это относится к другой команде SET, такой как "SET NOCOUNT ON"

Ответ 12

if (set no count == off)

{ то он будет хранить данные о том, сколько записей было затронуто поэтому снижайте производительность } еще { он не будет отслеживать запись изменений следовательно, улучшить перфоманс } }

Ответ 13

Я знаю, это довольно старый вопрос. но только для обновления.

Лучший способ использовать "SET NOCOUNT ON" - поставить его в качестве первого оператора в вашем SP и снова отключить его перед предыдущим оператором SELECT.

Ответ 14

Ademas de lo hablado, el suprimir SET NOCOUNT ON, puede hacer que al recoger un valor devuelto en un store процедура pendiente un SELECT, no se capturado por VB60 u otros lenguajes. Al incluir la instructioncción SET NOCOUNT ON, funciona correctamente. Es curioso ver como en el Administrador Corporativo siempre funciona bien.

Ответ 15

Иногда даже самые простые вещи могут иметь значение. SET NOCOUNT ON один из этих простых элементов, которые должны быть частью каждой хранимой процедуры. Эта строка кода, расположенная в верхней части хранимой процедуры, отключает сообщения, которые SQL Server отправляет обратно клиенту после выполнения каждого оператора T-SQL. Это выполняется для всех SELECT, INSERT, UPDATE и DELETE. Наличие этой информации удобно при запуске оператора T-SQL в окне запроса, но когда выполняются хранимые процедуры, нет необходимости передавать эту информацию клиенту.

Удаление этих дополнительных служебных данных из сети может значительно повысить общую производительность вашей базы данных и приложения.

Если вам все еще нужно получить количество строк, на которые влияет оператор T-SQL, который выполняется, вы все равно можете использовать опцию @@ROWCOUNT. Выпустив SET NOCOUNT ON эта функция (@@ROWCOUNT) по-прежнему работает и может использоваться в ваших хранимых процедурах для определения количества строк, затронутых оператором.

Ответ 16

Единственное место, в котором SET NOCOUNT ON действительно может помочь, - это когда вы делаете запросы в цикле или курсоре. Это может добавить много сетевого трафика.

CREATE PROCEDURE NoCountOn
AS
set nocount on
    DECLARE @num INT = 10000
    while @num > 0
    begin
       update MyTable SET SomeColumn=SomeColumn
       set @num = @num - 1
    end
GO


CREATE PROCEDURE NoCountOff
AS
set nocount off
    DECLARE @num INT = 10000
    while @num > 0
    begin
       update MyTable SET SomeColumn=SomeColumn
       set @num = @num - 1
    end
GO

Включение клиентской статистики в SSMS, запуск EXEC NoCountOn и EXEC NoCountOff показывает, что на NoCountOff был дополнительный трафик 390 КБ:

client statistics

Вероятно, не идеально, чтобы делать запросы в цикле или курсоре, но мы не живем и в идеальном мире :)