ESTABLECER UNA CUENTA DE USO

341

Inspirado por esta pregunta donde hay diferentes puntos de vista en SET NOCOUNT ...

¿Deberíamos usar SET NOCOUNT ON para SQL Server? ¿Si no, porque no?

Que hace Edit 6, el 22 de julio de 2011

Suprime el mensaje "xx filas afectadas" después de cualquier DML. Este es un conjunto de resultados y cuando se envía, el cliente debe procesarlo. Es pequeño, pero medible (ver las respuestas a continuación)

Para los desencadenantes, etc., el cliente recibirá múltiples "filas xx afectadas" y esto causa todo tipo de errores para algunos ORM, MS Access, JPA, etc. (vea las ediciones a continuación)

Antecedentes:

La práctica recomendada general aceptada (pensé hasta esta pregunta) es usarla SET NOCOUNT ONen disparadores y procedimientos almacenados en SQL Server. Lo usamos en todas partes y un google rápido muestra muchos MVP de SQL Server que también están de acuerdo.

MSDN dice que esto puede romper un .net SQLDataAdapter .

Ahora, esto significa para mí que el SQLDataAdapter se limita a un procesamiento CRUD completamente simple porque espera que el mensaje "n filas afectadas" coincida. Entonces, no puedo usar:

  • SI EXISTE para evitar duplicados (mensaje sin filas afectadas) Nota: use con precaución
  • DONDE NO EXISTE (menos filas de lo esperado
  • Filtre las actualizaciones triviales (por ejemplo, no hay datos que realmente cambien)
  • Haga cualquier acceso a la tabla antes (como el registro)
  • Ocultar complejidad o desnormalización
  • etc.

En la pregunta marc_s (quién sabe sus cosas de SQL) dice que no lo use. Esto difiere de lo que pienso (y también me considero algo competente en SQL).

Es posible que me esté perdiendo algo (siéntase libre de señalar lo obvio), pero ¿qué piensan ustedes por ahí?

Nota: han pasado años desde que vi este error porque no uso SQLDataAdapter hoy en día.

Ediciones después de comentarios y preguntas:

Editar: Más pensamientos ...

Tenemos varios clientes: uno puede usar un C # SQLDataAdaptor, otro puede usar nHibernate de Java. Estos pueden verse afectados de diferentes maneras con SET NOCOUNT ON.

Si considera los procedimientos almacenados como métodos, entonces es una mala forma (antipatrón) asumir que algunos procesamientos internos funcionan de cierta manera para sus propios fines.

Edición 2: un disparador que rompe la pregunta nHibernate , donde SET NOCOUNT ONno se puede configurar

(y no, no es un duplicado de esto )

Edición 3: Aún más información, gracias a mi colega MVP

Edición 4: 13 de mayo de 2011

¿Rompe Linq 2 SQL también cuando no se especifica?

Edición 5: 14 jun 2011

Rompe JPA, proceso almacenado con variables de tabla: ¿JPA 2.0 admite variables de tabla de SQL Server?

Edición 6: 15 ago 2011

La cuadrícula de datos "Editar filas" de SSMS requiere SET NOCOUNT ON: Actualizar disparador con GROUP BY

Edición 7: 07 mar 2013

Detalles más detallados de @RemusRusanu:
¿SET NOCOUNT ON realmente hace una gran diferencia de rendimiento?

gbn
fuente
@AlexKuznetsov: ¿Cuál sería un enfoque "Threadsafe"? ¿Seguramente las lecturas realizadas en EXISTS seguirían incluyendo alguna transacción pendiente?
AnthonyWJones
2
@ Jeremy Seghi: perdón por la respuesta tardía. El mensaje (#rows afectadas) es una herramienta de cliente interpretada por SSMS, etc. Sin embargo, se envía un paquete con esta información. Por supuesto, soy consciente de cómo funciona @@ rowcount, etc., pero este no es el punto de la pregunta ...
gbn
1
Sin preocupaciones. Personalmente estoy de acuerdo con tu punto de vista; Estaba comentando que no existe una correlación directa entre los resultados de una construcción IF / WHERE EXISTS y SET NOCOUNT. Obtengo resultados consistentes de esas construcciones independientemente de NOCOUNT. Si tiene algo que diga lo contrario, envíelo a mi manera.
Jeremy S
1
@Jeremy Seghi: tiene razón: SET NOCOUNT ON solo suprime el paquete adicional de datos al cliente. SI, @@ ROWCOUNT, etc., no se ven afectados. Ah, y rompe SQLDataAdapters ... :-)
gbn
1
@Kieren Johnstone: en retrospectiva, es una pregunta mal formulada. Yo votaría para cerrar si esta no fuera mi pregunta ...
gbn

Respuestas:

245

Ok, ahora he hecho mi investigación, aquí está el trato:

En el protocolo TDS, SET NOCOUNT ONsolo guarda 9 bytes por consulta, mientras que el texto "SET NOCOUNT ON" en sí es la friolera de 14 bytes. Solía ​​pensar que 123 row(s) affectedse devolvió del servidor en texto plano en un paquete de red separado, pero ese no es el caso. De hecho, es una pequeña estructura llamada DONE_IN_PROCincrustada en la respuesta. No es un paquete de red separado, por lo que no se desperdician viajes de ida y vuelta.

Creo que puede mantener el comportamiento de conteo predeterminado casi siempre sin preocuparse por el rendimiento. Sin embargo, hay algunos casos en los que calcular el número de filas de antemano afectaría el rendimiento, como un cursor de solo avance. En ese caso, NOCOUNT podría ser una necesidad. Aparte de eso, no hay absolutamente ninguna necesidad de seguir el lema "usar NOCOUNT siempre que sea posible".

Aquí hay un análisis muy detallado sobre la insignificancia de la SET NOCOUNTconfiguración: http://daleburnett.com/2014/01/everything-ever-wanted-know-set-nocount/

Sedat Kapanoglu
fuente
En efecto. He estado usando SET NOCOUNT ON para siempre, pero marc_s señaló la limitación de SQLDataAdapter en la otra pregunta.
gbn
Gracias. Los bytes o el tamaño no son el problema para mí, pero el cliente tiene que procesarlo. Es la dependencia SQLDataAdapter que todavía me sorprende, aunque ...
GBN
2
Gracias por tu respuesta. Aceptaré esto debido a tus investigaciones, que provocaron más información y trabajo de mi parte. Sin embargo, no estoy de acuerdo con los gastos generales: puede ser importante, como muestran otras respuestas. Cheers, gbn
gbn
13
No es el número de bytes de la demora de ida y vuelta sobre el alambre que es el asesino rendimiento
racingsnail
1
En la secuencia de mensajes TDS, y el ejemplo es cuando uno está insertando solo valores en la tabla. DONINPROCEl DONEmensaje (RPC) o (BATCH) se transmite con el rowcountconjunto a las filas afectadas, mientras que el done_countindicador es true, independientemente de si NO_COUNTes así ON. Depende de la implementación de la biblioteca del cliente en los casos en que la consulta contiene sentencias SELECT o llamadas RPC que sí seleccionan, puede requerir deshabilitar el conteo ... CUANDO está deshabilitado, las filas todavía se cuentan para la instrucción select, pero el indicador DONE_COUNTestá configurado en false. Siempre lea lo que su cliente lib sugiere, ya que interpretará el flujo de token (mensaje) en lugar de usted
Milan Jaric
86

Me llevó mucho tiempo encontrar cifras reales de referencia en torno a NOCOUNT, así que pensé en compartir un resumen rápido.

  • Si su procedimiento almacenado usa un cursor para realizar muchas operaciones muy rápidas sin resultados devueltos, tener NOCOUNT OFF puede tomar aproximadamente 10 veces más tiempo que tenerlo activado. 1 Este es el peor de los casos.
  • Si su procedimiento almacenado solo realiza una única operación rápida sin resultados devueltos, establecer NOCOUNT ON podría producir un aumento del rendimiento de alrededor del 3%. 2 Esto sería coherente con un procedimiento típico de inserción o actualización. (Vea los comentarios sobre esta respuesta para una discusión sobre por qué esto puede no ser siempre más rápido).
  • Si su procedimiento almacenado devuelve resultados (es decir, SELECCIONA algo), la diferencia de rendimiento disminuirá proporcionalmente con el tamaño del conjunto de resultados.
StriplingWarrior
fuente
55
+1 para el impacto en el cursor, esto es consistente con mis observaciones
zvolkov
¡El punto 2 no es exacto! Me refiero al blog al que se refiere. ¡Nunca fue! DONE y DONEPROC y DONEINPROC se envían con el mismo tamaño, independientemente de si NO_COUNT está activado o desactivado. RowCount todavía está allí como ULONGLONG (64 bytes) y el indicador DONE_COUNT todavía está allí, pero el valor de bit es 0. El servidor SQL contará el número de filas de todos modos, incluso si no está interesado en leer el valor del token HECHO. Si lees @@ ROWCOUNT, entonces agregaste más bytes a la secuencia de tokens, ya sea en forma de token returnvalue o como otro token de colmetadata + fila.
Milan Jaric
@ MilanJaric: Gracias por llamar eso. Me ayudaste a darme cuenta de que había vinculado el artículo equivocado. El enlace se actualiza ahora y el artículo presenta un argumento convincente para mostrar que puede haber una ligera mejora en el rendimiento con SET NOCOUNT ON. ¿Crees que hay problemas con los métodos de referencia utilizados?
StriplingWarrior
:) todavía es impreciso sobre SET NOCOUNT OFF / ON, el error es que el segundo SP no tiene SET NOCOUNT OFF;y es por eso que piensan que no están obteniendo bytes adicionales en respuesta. El punto de referencia exacto sería utilizarlo SET NOCOUNT ONen el SET NOCOUNT OFFprocedimiento almacenado a la izquierda y a la derecha. De esta manera, obtendrá el paquete TDS con DONEINPROC (SET NOCOUNT ...)diez de nuevo DONEINPROC (INSERT statement), y luego RETURNVALUE(@@ROWCOUNT), RETURNSTATUS 0para sp y finalmente DONPROC. ¡El error está ahí porque el segundo sp no tiene SET NOCOUNT OFF en el cuerpo!
Milan Jaric
Para reformular lo que encontraron pero no se dieron cuenta es que si tiene una solicitud de cursor de búsqueda de 1K, primero haga una solicitud para establecer NOCOUNT en ON u OFF para la conexión y luego use la misma conexión para llamar a la búsqueda de cursor 1K veces para ahorrar algo de ancho de banda. El estado de conexión real para NOCOUNT ON u OFF no afectará el ancho de banda, solo puede confundir la biblioteca del cliente, por ejemplo, ADO.net u ODBC. Así que "no uses SET NOCOUNT <WHATEVER> si te importa el ancho de banda" :)
Milan Jaric
77
  • Cuando SET NOCOUNT está activado, el recuento (que indica el número de filas afectadas por una instrucción Transact-SQL) no se devuelve. Cuando SET NOCOUNT está desactivado, se devuelve el recuento. Se usa con cualquier instrucción SELECT, INSERT, UPDATE, DELETE.

  • La configuración de SET NOCOUNT se establece en tiempo de ejecución o ejecución y no en tiempo de análisis.

  • SET NOCOUNT ON mejora el rendimiento del procedimiento almacenado (SP).

  • Sintaxis: SET NOCOUNT {ON | APAGADO }

Ejemplo de SET NOCOUNT ON:

ingrese la descripción de la imagen aquí

Ejemplo de SET NOCOUNT OFF:

ingrese la descripción de la imagen aquí

Bhaumik Patel
fuente
77
Fácil y rápido de entender con capturas de pantalla. Gran trabajo. :)
shaijut
35

Supongo que hasta cierto punto es un problema de DBA vs. desarrollador.

Como desarrollador en su mayoría, diría que no lo use a menos que sea absolutamente necesario, porque usarlo puede romper su código ADO.NET (según lo documentado por Microsoft).

Y supongo que como DBA, estarías más del otro lado: úsalo siempre que sea posible a menos que realmente debas evitar su uso.

Además, si sus desarrolladores alguna vez usan los "Registros afectados" que devuelve la ExecuteNonQueryllamada al método de ADO.NET , están en problemas si todos los usan, SET NOCOUNT ONya que en este caso, ExecuteNonQuery siempre devolverá 0.

También vea la publicación del blog de Peter Bromberg y revise su posición.

Entonces, todo se reduce a quién puede establecer los estándares :-)

Bagazo

marc_s
fuente
Está en aproximadamente CRUD sencillo sin embargo: la cuadrícula de datos que menciona podría utilizar XML para enviar múltiples filas para evitar idas y vueltas, etc
GBN
Supongo que si nunca usa SqlDataAdapters, y nunca busca y confía en el número de "registros afectados" devuelto por ExecuteNonQuery (por ejemplo, si usa algo como Linq-to-SQL o NHibernate), entonces probablemente no tenga ningún problema usando SET NOCOUNT ON en todos los procesos almacenados.
marc_s
12

Si está diciendo que también podría tener diferentes clientes, hay problemas con ADO clásico si SET NOCOUNT no está activado.

Uno que experimento regularmente: si un procedimiento almacenado ejecuta una serie de declaraciones (y, por lo tanto, se devuelven varios mensajes de "xxx filas afectadas"), ADO parece no manejar esto y arroja el error "No se puede cambiar la propiedad ActiveConnection de un objeto Recordset que tiene un objeto Command como fuente ".

Por lo tanto, generalmente recomiendo activarlo a menos que haya una muy buena razón para no hacerlo. Es posible que haya encontrado la muy buena razón por la que necesito ir y leer más.

Chris J
fuente
9

A riesgo de hacer las cosas más complicadas, animo una regla ligeramente diferente a todas las que veo arriba:

  • Establezca siempre NOCOUNT ONen la parte superior de un proceso, antes de realizar cualquier trabajo en el proceso, pero también siempre de SET NOCOUNT OFFnuevo, antes de devolver cualquier conjunto de registros del proceso almacenado.

Entonces, "generalmente no cuente, excepto cuando en realidad está devolviendo un conjunto de resultados". No sé de qué manera esto puede romper cualquier código de cliente, significa que el código de cliente nunca necesita saber nada sobre los procesos internos, y no es particularmente oneroso.

Tao
fuente
Gracias. Puede obtener un recuento de filas desde el DataSet o el contenedor de consumo, por supuesto, pero podría ser útil. No podemos tener desencadenantes en SELECT, por lo que esto sería seguro: la mayoría de los errores del cliente son causados ​​por mensajes espurios en los cambios de datos.
gbn
El problema con esta regla es que es más difícil de probar que "¿ESTA ESTA CONFIGURADO EN LA PARTE SUPERIOR del proceso?"; Me pregunto si las herramientas de análisis SQL como Sql Enlight pueden probar ese tipo de cosas ... Agregarlo a mi lista de tareas a largo plazo para mi proyecto de formateador SQL :)
Tao
5

Con respecto a los desencadenantes que rompen NHibernate, tuve esa experiencia de primera mano. Básicamente, cuando NH hace una ACTUALIZACIÓN, espera cierto número de filas afectadas. Al agregar SET NOCOUNT ON a los disparadores, obtiene el número de filas de nuevo a lo que NH esperaba, solucionando así el problema. Así que sí, definitivamente recomendaría desactivarlo para los desencadenantes si usa NH.

En cuanto al uso en SP, es una cuestión de preferencia personal. Siempre había desactivado el recuento de filas, pero, de nuevo, no hay argumentos realmente fuertes de ninguna manera.

En una nota diferente, realmente debería considerar alejarse de la arquitectura basada en SP, entonces ni siquiera tendrá esta pregunta.

zvolkov
fuente
1
No estoy de acuerdo con alejarme de los procesos almacenados. Esto significaría que tenemos que tener el mismo SQL en 2 bases de códigos de clientes diferentes y confiar en nuestros codificadores de clientes. Somos desarrolladores de DBA. Y qué no decir "SET NOCOUNT EN "?
gbn
@CodeBlend: solo búscalo en Google por más de lo que necesitas. Sin embargo ... stackoverflow.com/a/4040466/27535
gbn
3

Quería verificar que 'SET NOCOUNT ON' no guarda un paquete de red ni un viaje de ida y vuelta

Utilicé un SQLServer 2017 de prueba en otro host (utilicé una 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 Luego rastreé los paquetes en el puerto 1433 con la herramienta 'Wireshark': botón 'capturar filtro' -> 'puerto 1433'

exec procNoCount

Este es el paquete de respuesta: 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 es el paquete de respuesta: 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

En la línea 40 puedo ver '07', que es el número de 'filas afectadas'. Se incluye en el paquete de respuesta. Sin paquete extra.

Sin embargo, tiene 13 bytes adicionales que podrían guardarse, pero probablemente no valen más que reducir los nombres de columna (por ejemplo, 'ManagingDepartment' a 'MD')

Así que no veo ninguna razón para usarlo para el rendimiento

PERO, como otros mencionaron, puede romper ADO.NET y también me topé con un problema usando python: MSSQL2008 - Pyodbc - El SQL anterior no era una consulta

Entonces, probablemente sea un buen hábito ...

phil_w
fuente
1
SET NOCOUNT ON;

Esta línea de código se usa en SQL para no devolver las filas de números afectadas en la ejecución de la consulta. Si no requerimos el número de filas afectadas, podemos usar esto ya que esto ayudaría a ahorrar el uso de memoria y aumentaría la velocidad de ejecución de la consulta.

usuario1509
fuente
2
Tenga en cuenta que @@ ROWCOUNT todavía está configurado. SET NOCOUNT ON suprime cualquier respuesta adicional que SQL Server envía al cliente. Vea la respuesta aceptada arriba por favor
gbn
1

ESTABLECER CUENTA El código anterior detendrá el mensaje generado por el motor del servidor sql en la ventana de resultados frontal después de la ejecución del comando DML / DDL.

¿Por qué lo hacemos? Como el motor del servidor SQL toma algunos recursos para obtener el estado y generar el mensaje, se considera una sobrecarga en el motor del servidor SQL. Por lo tanto, configuramos el mensaje de no cuenta.

Panda Subhransu
fuente
1

Un lugar que SET NOCOUNT ONrealmente puede ayudar es donde está haciendo consultas en un bucle o un cursor. Esto puede sumar mucho tráfico de red.

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

Al activar las estadísticas del cliente en SSMS, se ejecuta EXEC NoCountOny EXEC NoCountOffmuestra que hubo un tráfico adicional de 390 KB en el NoCountOff:

estadísticas del cliente

Probablemente no sea ideal para hacer consultas en un bucle o cursor, pero tampoco vivimos en el mundo ideal :)

bcoughlan
fuente
0

Sé que es una pregunta bastante antigua. Pero solo para actualizar.

La mejor manera de usar "SET NOCOUNT ON" es ponerlo como una primera declaración en su SP y volverlo a APAGAR justo antes de la última declaración SELECT.

KRules
fuente
-1

No sé cómo probar SET NOCOUNT ON entre el cliente y SQL, así que probé un comportamiento similar para otro comando SET "SET TRANSACTION ISVELATION LEVEL LEAD UNCIMMITTED"

Envié un comando desde mi conexión cambiando el comportamiento predeterminado de SQL (READ COMMITTED), y se cambió para los siguientes comandos. Cuando cambié el nivel de AISLAMIENTO dentro de un procedimiento almacenado, no cambió el comportamiento de conexión para el siguiente comando.

Conclusión actual

  1. Cambiar la configuración dentro del procedimiento almacenado no cambia la configuración predeterminada de la conexión.
  2. Cambiar la configuración enviando comandos usando ADOCOnnection cambia el comportamiento predeterminado.

Creo que esto es relevante para otros comandos SET como "SET NOCOUNT ON"

Rabia Mansour
fuente
¿Su punto 1 anterior implica que realmente no necesita DESACTIVAR LA CUENTA al final porque no afecta el entorno global?
funkymushroom
No estoy seguro de si eso es lo que quiso decir con el punto 1, pero en mis pruebas sí, aparentemente el entorno global no se ve afectado por SET NOCOUNT ON dentro de un procedimiento almacenado.
Doug
Esta fue una mala elección de comparación, porque el Nivel de aislamiento está explícitamente relacionado con una transacción en particular, por lo que no hay ninguna razón en particular para esperar que sea consistente con una configuración comoNOCOUNT
IMSoP
-1

if (establecer sin recuento == off)

{entonces mantendrá datos de cuántos registros afectados, así que reduzca el rendimiento} más {no rastreará el registro de cambios, por lo tanto, mejorará el rendimiento}}

Shubham Sharma
fuente
-1

A veces, incluso las cosas más simples pueden marcar la diferencia. Uno de estos elementos simples que deberían formar parte de cada procedimiento almacenado es SET NOCOUNT ON. Esta línea de código, colocada en la parte superior de un procedimiento almacenado, apaga los mensajes que SQL Server envía al cliente después de que se ejecuta cada instrucción T-SQL. Esto se realiza para todas SELECT, INSERT, UPDATE, y DELETEdeclaraciones. Tener esta información es útil cuando ejecuta una instrucción T-SQL en una ventana de consulta, pero cuando se ejecutan los procedimientos almacenados, no es necesario que esta información se devuelva al cliente.

Al eliminar esta sobrecarga adicional de la red, puede mejorar en gran medida el rendimiento general de su base de datos y aplicación.

Si aún necesita obtener el número de filas afectadas por la instrucción T-SQL que se está ejecutando, aún puede usar la @@ROWCOUNTopción. Al emitir una SET NOCOUNT ONfunción this ( @@ROWCOUNT) todavía funciona y aún se puede usar en sus procedimientos almacenados para identificar cuántas filas se vieron afectadas por la instrucción.

Vinayak Savale
fuente