¿Por qué SQL Server devuelve algunas filas mientras todavía ejecuta la consulta, y a veces no?


33

Hay consultas en las que cuando presionamos "ejecutar", muestra algunas filas y sigue creciendo, pero la consulta aún no ha terminado. Sin embargo, a veces, espera hasta el final de la consulta.

¿Por qué pasó esto? ¿Hay alguna manera de controlar esto?

Respuestas:


43

La respuesta, como de costumbre (está bien, la mayoría de las veces), se encuentra en el plan de ejecución.

Hay ciertos operadores que requieren que todas las filas lleguen a ellos antes de que puedan comenzar a procesar esas filas y pasarlas aguas abajo, por ejemplo:

  • Hash Join (en la construcción de la tabla hash)
  • Hash Match
  • Ordenar (excepto Hash Flow Distinct)

Se les llama bloqueo o operadores de detención y avance debido a esto, y a menudo se eligen cuando el optimizador piensa que tendrá que procesar una gran cantidad de datos para encontrar sus datos.

Hay otros operadores que pueden comenzar a transmitir o pasar cualquier fila encontrada inmediatamente.

  • Bucles anidados
  • Index soporta Merge Joins
  • Agregados de flujo

Cuando las consultas comienzan a devolver datos de inmediato, pero no terminan de inmediato, generalmente es una señal de que el optimizador eligió un plan para ubicar y devolver algunas filas rápidamente utilizando operadores que tienen un costo inicial más bajo.

Esto puede suceder debido a los objetivos de fila introducidos por usted o por el optimizador.

También puede ocurrir si se elige un mal plan por alguna razón (falta de SARGability, rastreo de parámetros, estadísticas insuficientes, etc.), pero eso requiere más investigación para descubrirlo.

Para obtener más información, consulte el blog de Rob Farley aquí.

Y la serie de Paul White sobre goles en fila aquí , aquí , aquí y aquí .

También debe tenerse en cuenta que, si habla de SSMS, las filas solo aparecen una vez que se ha llenado un búfer completo, no solo de forma involuntaria.


14

Si entiendo lo que está observando, así es como Management Studio representa las filas y tiene poco que ver con cómo SQL Server devuelve filas. De hecho, a menudo, cuando devuelve resultados grandes a SSMS e intenta representarlos en una cuadrícula, SSMS no puede mantener el ritmo y SQL Server termina esperando que la aplicación procese más filas. En este caso, verá las ASYNC_NETWORK_IOesperas acumuladas de SQL Server .

Puede controlarlo de alguna manera usando Resultados a texto en lugar de Resultados a cuadrícula, ya que SSMS puede dibujar texto más rápido de lo que puede dibujar cuadrículas, pero es probable que esto afecte la legibilidad dependiendo del número de columnas y los tipos de datos involucrados. Ambos se ven afectados cuando SSMS decide escribir los resultados en ese panel, que depende de qué tan lleno esté el búfer de salida.

Cuando tiene varias declaraciones y desea forzar al búfer para que muestre los resultados de salida en el panel de mensajes, puede usar un pequeño truco de impresión entre las declaraciones:

RAISERROR('', 0, 1) WITH NOWAIT;

Pero esto no ayudará cuando intente hacer que SSMS represente filas más rápidamente cuando toda la salida proviene de una sola declaración.

Más directamente, puede controlarlo limitando la cantidad de resultados que está generando en SSMS. A menudo veo que la gente se queja de cuánto tiempo lleva devolver un millón de filas a la cuadrícula. No tengo idea de qué demonios hará alguien con un millón de filas en una cuadrícula SSMS.

Hay algunos hacks como OPTION (FAST 100), que se optimizarán para recuperar esas primeras 100 filas (o cualquier 100 filas si no hay exterior ORDER BY), pero esto puede tener el costo de una recuperación mucho más lenta para el resto de las filas y un plan que es más ineficiente en general, por lo que no es realmente una opción ir en mi humilde opinión.


1

Su pregunta no es sobre SQLServer per se sino:

  • Servidor SQL
  • red
  • SSMS como aplicación cliente

¿Hay alguna manera de controlar esto?

Respuesta corta :

  1. Pruebe en sqlcmdlugar de ssmso sqlcmd-mode dessms
  2. Verifique su conexión y configuración de sesión

Respuesta larga :

¡Por supuesto! Pero no uno - problema

  1. Ejecute su consulta con sqlcmdo en sqlcmdmodo en ssms.
  2. Si desea excluir la función de red, ejecute su consulta en el servidor con conexión de memoria compartida.
  3. Si el rendimiento de la consulta no es satisfactorio incluso con la conexión de memoria compartida, analice sus planes de ejecución. Si la consulta funciona mal a través de la red, llame a su administrador de red para obtener ayuda. Si su consulta funciona mal solo en SSMS, siga leyendo.
  4. Ahora estamos seguros de que los problemas están del lado del cliente (ssms en este caso). Mire la configuración de conexión y sesión en SSMS. No crea en la interfaz ssms y verifique con SQL Profiler: encuentre su conexión spidy obtendrá una lista completa de la configuración de la sesión. Comparar con la configuración de la sqlcmdsesión. Si nada hace clic: copie todas las configuraciones de sesión del generador de perfiles en su script de consulta, ejecute en sqlcmdmodo y cambiando gradualmente las configuraciones encontrará a su culpable.

¡Buena suerte!


-2

Para agregar a la respuesta de sp_BlitzErik, tome el ejemplo usando a NOT IN ()con una sub selección. Para determinar si un elemento está en el resultado de la consulta anidada, (generalmente) es necesario recuperar el resultado completo.

Entonces, una forma fácil de mejorar el rendimiento de tales consultas es reescribirlas como LEFT OUTER JOINdonde la condición para el RIGHTlado es nula (por supuesto, ¿podría cambiarlo, pero quién lo usa RIGHT OUTER JOINS?). Esto permite que los resultados comiencen a regresar de inmediato.


No lo creo. Si las columnas comparadas no son anulables, entonces los resultados deberían ser los mismos y los planes, generalmente, los mismos, para las 3 versiones de un anti-unión (NO EN, NO EXISTE, IZQUIERDA UNIR / ES NULO). No es necesario recuperar todo el resultado.
ypercubeᵀᴹ

Si la subselección es realmente compleja, la consulta producida necesita evaluar toda la subselección antes de verificar la condición NO ENCENDIDO, la UNIDAD WHERE t.x IN (<complex SELECT subquery>)IZQUIERDA equivalente LEFT JOIN (<complex SELECT subquery>) AS r ON r.x = t.x .... WHERE r.x IS NULL, entonces la subconsulta también tendrá que ser evaluada (así que el mismo plan complejo con el NO EN versión).
ypercubeᵀᴹ

@ ypercubeᵀᴹ Me funcionó en el pasado. He visto que las consultas pasan de tomar minutos para volver al segundo.
JimmyJames

@ ypercubeᵀᴹ Junté un ejemplo simple en Oracle (lo siento, no tengo acceso a SQLServer en este momento) y definitivamente tenían diferentes planes de explicación. Quizás no fueron diferencias significativas, pero se ven bastante diferentes.
JimmyJames

@JimmyJames: no es una forma simple si desea un rendimiento estable y tales "optimizaciones" son muy sensibles para la versión de SQLServer. Y no cometa errores apelando a Oracle (¿qué versión?). Históricamente SQLServer prefería NOT EXISTSpero Oracle NOT INen las consultas. Pero hoy debe considerarse como un error en el generador de planes
Alex Yu
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.