Inspirado por esta pergunta, em que existem diferentes pontos de vista sobre SET NOCOUNT ...
Devemos usar SET NOCOUNT ON para SQL Server? Se não, por que não?
O que faz Edit 6, on 22 Jul 2011
Suprime a mensagem "xx linhas afetadas" após qualquer DML. Este é um conjunto de resultados e, quando enviado, o cliente deve processá-lo. É pequeno, mas mensurável (veja as respostas abaixo)
Para gatilhos, etc, o cliente receberá várias "linhas xx afetadas" e isso causa todos os tipos de erros para alguns ORMs, MS Access, JPA etc. (veja as edições abaixo)
Fundo:
A melhor prática geral aceita (pensei até essa pergunta) é usar SET NOCOUNT ON
gatilhos e procedimentos armazenados no SQL Server. Nós o usamos em qualquer lugar e um rápido google mostra muitos MVPs do SQL Server também.
MSDN diz que isso pode quebrar um .net SQLDataAdapter .
Agora, isso significa para mim que o SQLDataAdapter está limitado ao processamento de CRUD simplesmente porque espera que a mensagem "n linhas afetadas" corresponda. Então, eu não posso usar:
- SE EXISTE para evitar duplicatas (nenhuma linha afetou a mensagem) Nota: use com cuidado
- ONDE NÃO EXISTE (menos linhas do que o esperado
- Filtrar atualizações triviais (por exemplo, nenhum dado realmente muda)
- Faça qualquer acesso à tabela antes (como o log)
- Ocultar complexidade ou denormlisation
- etc
Na pergunta marc_s (quem conhece o seu material SQL) diz que não o usa. Isso difere do que penso (e também me considero um pouco competente em SQL).
É possível que eu esteja perdendo alguma coisa (sinta-se à vontade para apontar o óbvio), mas o que vocês acham?
Nota: já faz anos que não vejo esse erro porque não uso o SQLDataAdapter atualmente.
Edita após comentários e perguntas:
Edit: Mais pensamentos ...
Temos vários clientes: um pode usar um C # SQLDataAdaptor, outro pode usar o nHibernate do Java. Estes podem ser afetados de diferentes maneiras com SET NOCOUNT ON
.
Se você considerar procs armazenados como métodos, é uma má forma (antipadrão) supor que algum processamento interno funcione de certa maneira para seus próprios propósitos.
Edit 2: uma questão nHibernate de trigger trigger , onde SET NOCOUNT ON
não pode ser definida
(e não, não é uma duplicata disso )
Edit 3: Mais informações, graças ao meu colega MVP
- KB 240882 , problema que causa desconexões no SQL 2000 e versões anteriores
- Demonstração de ganho de desempenho
Edit 4: 13 de maio de 2011
Quebra Linq 2 SQL também quando não especificado?
Edit 5: 14 Jun 2011
Quebra JPA, processo armazenado com variáveis de tabela: O JPA 2.0 suporta variáveis de tabela do SQL Server?
Edit 6: 15 de agosto de 2011
A grade de dados "Editar linhas" do SSMS requer SET NOCOUNT ON: atualize o gatilho com GROUP BY
Edit 7: 07 Mar 2013
Detalhes mais detalhados do @RemusRusanu:
O SET NOCOUNT ON realmente faz muita diferença de desempenho
Respostas:
Ok, agora eu fiz minha pesquisa, eis o negócio:
No protocolo TDS,
SET NOCOUNT ON
salva apenas 9 bytes por consulta, enquanto o próprio texto "SET NOCOUNT ON" possui 14 bytes. Eu costumava pensar que123 row(s) affected
era retornado do servidor em texto sem formatação em um pacote de rede separado, mas esse não é o caso. Na verdade, é uma pequena estrutura chamadaDONE_IN_PROC
incorporada na resposta. Não é um pacote de rede separado, portanto não são desperdiçadas ida e volta.Eu acho que você pode manter o comportamento padrão de contagem quase sempre sem se preocupar com o desempenho. Existem alguns casos em que o cálculo antecipado do número de linhas afetaria o desempenho, como um cursor somente para frente. Nesse caso, NOCOUNT pode ser uma necessidade. Fora isso, não há absolutamente nenhuma necessidade de seguir o lema "use NOCOUNT, sempre que possível".
Aqui está uma análise muito detalhada sobre a insignificância da
SET NOCOUNT
configuração: http://daleburnett.com/2014/01/everything-ever-wanted-know-set-nocount/fonte
DONINPROC
(RPC) ouDONE
(BATCH) são transmitidas comrowcount
as linhas afetadas, enquanto odone_count
sinalizador étrue
, independentemente deNO_COUNT
serON
. Depende da implementação da lib do cliente nos casos em que a consulta contém instruções SELECT ou chamadas RPC que selecionam, pode ser necessário desativar a contagem ... QUANDO desativada, as linhas ainda são contadas para a instrução select, mas o sinalizadorDONE_COUNT
está definido comofalse
. Sempre leia o que o seu lib cliente sugere uma vez que irá interpretar símbolo (mensagem) transmitir ao invés de vocêDemorei bastante para encontrar números de referência reais em torno de NOCOUNT, então achei que compartilharia um resumo rápido.
fonte
SET NOCOUNT OFF;
e é por isso que eles acham que não estão recebendo bytes extras em resposta. O benchmark preciso seria usarSET NOCOUNT ON
noSET NOCOUNT OFF
procedimento armazenado à esquerda e à direita. Dessa forma, você obterá o pacote TDS comDONEINPROC (SET NOCOUNT ...)
, dez novamenteDONEINPROC (INSERT statement)
eRETURNVALUE(@@ROWCOUNT)
, em seguida,RETURNSTATUS 0
para sp e finalmenteDONPROC
. Ocorreu um erro porque o segundo sp não possui SET NOCOUNT OFF no corpo!Quando SET NOCOUNT está ativado, a contagem (indicando o número de linhas afetadas por uma instrução Transact-SQL) não é retornada. Quando SET NOCOUNT está desativado, a contagem é retornada. É usado com qualquer instrução SELECT, INSERT, UPDATE, DELETE.
A configuração de SET NOCOUNT é definida no tempo de execução ou execução e não no tempo de análise.
SET NOCOUNT ON melhora o desempenho do procedimento armazenado (SP).
Sintaxe: SET NOCOUNT {ON | FORA }
Exemplo de SET NOCOUNT ON:
Exemplo de SET NOCOUNT OFF:
fonte
Eu acho que até certo ponto é um problema DBA vs. desenvolvedor.
Como desenvolvedor, eu diria que não o use, a menos que seja absolutamente necessário - porque usá-lo pode quebrar seu código ADO.NET (conforme documentado pela Microsoft).
E eu acho que como DBA, você estaria mais do outro lado - use-o sempre que possível, a menos que você realmente deva impedir seu uso.
Além disso, se seus desenvolvedores usam o "RecordsAffected" retornado pela
ExecuteNonQuery
chamada de método do ADO.NET , você terá problemas se todo mundo usarSET NOCOUNT ON
pois nesse caso, ExecuteNonQuery sempre retornará 0.Veja também a publicação no blog de Peter Bromberg e confira sua posição.
Então, realmente se resume a quem define os padrões :-)
Marc
fonte
Se você está dizendo que também pode ter clientes diferentes, há problemas com o ADO clássico se SET NOCOUNT não estiver ativado.
Um que eu experimento regularmente: se um procedimento armazenado executa várias instruções (e, portanto, são retornadas várias mensagens "xxx linhas afetadas"), o ADO parece não lidar com isso e gera o erro "Não é possível alterar a propriedade ActiveConnection de um objeto Recordset que tem um objeto de comando como fonte ".
Então, geralmente defendo ativá-lo, a menos que haja realmente uma boa razão para não fazê-lo . você pode ter encontrado a realmente boa razão pela qual preciso ler e ler mais.
fonte
Correndo o risco de tornar as coisas mais complicadas, incentivo uma regra ligeiramente diferente de todas as que vejo acima:
NOCOUNT ON
na parte superior de um proc, antes de executar qualquer trabalho no proc, mas também sempreSET NOCOUNT OFF
novamente, antes de retornar quaisquer conjuntos de registros do proc armazenado.Portanto, "geralmente mantenha a quantidade limitada, exceto quando você estiver retornando um conjunto de resultados". Não conheço nenhuma maneira de quebrar esse código de cliente, significa que o código do cliente nunca precisa saber nada sobre os procedimentos internos do proc, e não é particularmente oneroso.
fonte
Com relação aos gatilhos que quebram o NHibernate, eu tive essa experiência em primeira mão. Basicamente, quando o NH faz um UPDATE, ele espera um certo número de linhas afetadas. Ao adicionar SET NOCOUNT ON aos gatilhos, você obtém o número de linhas de volta ao que a NH esperava, corrigindo o problema. Então, sim, eu recomendaria definitivamente desativá-lo para gatilhos se você usar o NH.
Em relação ao uso em SPs, é uma questão de preferência pessoal. Eu sempre desliguei a contagem de linhas, mas, novamente, não há argumentos realmente fortes de qualquer maneira.
Em uma nota diferente, você realmente deve considerar se afastar da arquitetura baseada em SP e não terá essa pergunta.
fonte
Eu queria verificar se 'SET NOCOUNT ON' não salva um pacote de rede nem uma ida e volta
Usei um teste SQLServer 2017 em outro host (usei uma VM).
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
Em seguida, localizei pacotes na porta 1433 com a ferramenta 'Wireshark': botão 'capture filter' -> 'port 1433'exec procNoCount
este é o pacote de resposta:
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
este é o pacote de resposta:
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
Na linha 40, vejo '07', que é o número de 'linhas afetadas'. Está incluído no pacote de resposta. Nenhum pacote extra.
No entanto, possui 13 bytes extras que podem ser salvos, mas provavelmente não valem mais a pena do que reduzir os nomes das colunas (por exemplo, 'ManagingDepartment' para 'MD')
Portanto, não vejo razão para usá-lo para desempenho
MAS, como outros mencionaram, ele pode quebrar o ADO.NET e eu também deparei com um problema usando o python: MSSQL2008 - Pyodbc - SQL anterior não era uma consulta
Então, provavelmente, um bom hábito ainda ...
fonte
Essa linha de código é usada no SQL para não retornar o número de linhas afetadas na execução da consulta. Se não exigirmos o número de linhas afetadas, podemos usá-lo, pois isso ajudará a economizar o uso de memória e a aumentar a velocidade de execução da consulta.
fonte
DEFINIR NOCOUNT ON; O código acima interromperá a mensagem gerada pelo mecanismo do servidor sql na janela de resultado frontal após a execução do comando DML / DDL.
Por que fazemos isso? Como o mecanismo do servidor SQL utiliza algum recurso para obter o status e gerar a mensagem, ele é considerado uma sobrecarga para o mecanismo do servidor Sql.
fonte
Um lugar que
SET NOCOUNT ON
pode realmente ajudar é onde você está fazendo consultas em um loop ou cursor. Isso pode adicionar muito tráfego de rede.Ativando as estatísticas do cliente no SSMS, uma execução
EXEC NoCountOn
eEXEC NoCountOff
mostra que havia um tráfego extra de 390 KB no NoCountOff:Provavelmente não é o ideal para fazer consultas em loop ou cursor, mas também não vivemos no mundo ideal :)
fonte
Eu sei que é uma pergunta muito antiga. mas apenas para atualização.
A melhor maneira de usar "SET NOCOUNT ON" é colocá-lo como primeira instrução no seu SP e desativá-lo novamente pouco antes da última instrução SELECT.
fonte
Não sei como testar SET NOCOUNT ON entre cliente e SQL, por isso testei um comportamento semelhante para outro comando SET "SET TRANSACTION ISOLATION LEVEL LEIT UNCIMMITTED"
Enviei um comando da minha conexão alterando o comportamento padrão do SQL (READ COMMITTED) e ele foi alterado para os próximos comandos. Quando alterei o nível ISOLATION dentro de um procedimento armazenado, ele não alterou o comportamento da conexão para o próximo comando.
Conclusão atual,
Eu acho que isso é relevante para outro comando SET, como "SET NOCOUNT ON"
fonte
NOCOUNT
if (definir sem contagem == desativado)
{então manterá os dados de quantos registros foram afetados para reduzir o desempenho}, caso contrário {não rastreará o registro de alterações e, portanto, melhorará o desempenho}}
fonte
Às vezes, mesmo as coisas mais simples podem fazer a diferença. Um desses itens simples que devem fazer parte de todo procedimento armazenado é
SET NOCOUNT ON
. Essa linha de código, colocada na parte superior de um procedimento armazenado, desativa as mensagens que o SQL Server envia de volta ao cliente após a execução de cada instrução T-SQL. Isto é realizado para todosSELECT
,INSERT
,UPDATE
, eDELETE
declarações. Ter essas informações é útil quando você executa uma instrução T-SQL em uma janela de consulta, mas quando os procedimentos armazenados são executados, não é necessário que essas informações sejam passadas de volta ao cliente.Ao remover essa sobrecarga extra da rede, ele pode melhorar significativamente o desempenho geral do seu banco de dados e aplicativo.
Se você ainda precisar obter o número de linhas afetadas pela instrução T-SQL que está sendo executada, ainda poderá usar a
@@ROWCOUNT
opção Ao emitir uma,SET NOCOUNT ON
essa função (@@ROWCOUNT
) ainda funciona e ainda pode ser usada nos procedimentos armazenados para identificar quantas linhas foram afetadas pela instrução.fonte