Respuestas:
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:
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.
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.
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_IO
esperas 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.
Su pregunta no es sobre SQLServer per se sino:
¿Hay alguna manera de controlar esto?
Respuesta corta :
sqlcmd
lugar de ssms
o sqlcmd
-mode dessms
Respuesta larga :
¡Por supuesto! Pero no uno - problema
sqlcmd
o en sqlcmd
modo en ssms.spid
y obtendrá una lista completa de la configuración de la sesión. Comparar con la configuración de la sqlcmd
sesión. Si nada hace clic: copie todas las configuraciones de sesión del generador de perfiles en su script de consulta, ejecute en sqlcmd
modo y cambiando gradualmente las configuraciones encontrará a su culpable.¡Buena suerte!
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 JOIN
donde la condición para el RIGHT
lado 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.
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).
NOT EXISTS
pero Oracle NOT IN
en las consultas. Pero hoy debe considerarse como un error en el generador de planes