¿Cómo (y por qué) TOP impacta un plan de ejecución?

35

Para una consulta moderadamente compleja que estoy tratando de optimizar, noté que eliminar la TOP ncláusula cambia el plan de ejecución. Habría adivinado que cuando una consulta incluye TOP nel motor de la base de datos, se ejecutaría la consulta ignorando la TOPcláusula, y luego, al final, simplemente reduciría el resultado establecido a la n cantidad de filas que se solicitó. El plan de ejecución gráfico parece indicar que este es el caso, TOPes el "último" paso. Pero parece que están sucediendo más.

Mi pregunta es, ¿cómo (y por qué) una cláusula TOP n impacta el plan de ejecución de una consulta?

Aquí hay una versión simplificada de lo que está sucediendo en mi caso:

La consulta coincide con filas de dos tablas, A y B.

Sin la TOPcláusula, el optimizador estima que habrá 19k filas de la tabla A y 46k filas de la tabla B. El número real de filas devueltas es 16k para A y 13k para B. Se utiliza una coincidencia hash para unir estos dos conjuntos de resultados para un total de 69 filas (luego se aplica una ordenación). Esta consulta ocurre muy rápidamente.

Cuando agrego TOP 1001el optimizador no utiliza una coincidencia hash; en su lugar, primero ordena los resultados de la tabla A (la misma estimación / real de 19k / 16k) y realiza un bucle anidado contra la tabla B. El número estimado de filas para la tabla B ahora es 1, y lo extraño es que TOP nafecta directamente número estimado de ejecuciones (búsqueda de índice) contra B: parece ser siempre 2n + 1 , o en mi caso 2003. Esta estimación cambia en consecuencia si cambio TOP n. Por supuesto, dado que esta es una unión anidada, el número real de ejecuciones es 16k (el número de filas de la tabla A) y esto ralentiza la consulta.

El escenario real es un poco más complejo pero captura la idea / comportamiento básico. Ambas tablas se buscan utilizando búsquedas de índice. Esta es la edición Enterprise de SQL Server 2008 R2.

David
fuente
La consulta tiene una ORDER BYcláusula. Agregando TOPcambios en el plan donde ocurre este tipo, pero estoy más preocupado por cómo afecta el número de ejecuciones de búsquedas de índice en la tabla B ... (por supuesto, los dos pueden estar relacionados, no lo sé)
David
1
Discusión relacionada: la FAST num_rowssugerencia de consulta.
Remus Rusanu

Respuestas:

39

Hubiera adivinado que cuando una consulta incluye TOP n, el motor de la base de datos ejecuta la consulta ignorando la cláusula TOP, y luego al final simplemente reduce ese resultado establecido en el número n de filas que se solicitó. El plan de ejecución gráfico parece indicar que este es el caso: TOP es el "último" paso. Pero parece que están sucediendo más.

La forma en que se expresa lo anterior me hace pensar que puede tener una imagen mental incorrecta de cómo se ejecuta una consulta. Un operador en un plan de consulta no es un paso (donde el conjunto de resultados completo de un paso anterior es evaluado por el siguiente.

SQL Server utiliza un modelo de ejecución canalizado , donde cada operador expone métodos como Init () , GetRow () y Close () . Como sugiere el nombre GetRow () , un operador produce una fila a la vez a pedido (según lo requiera su operador principal). Esto está documentado en la referencia de Operadores físicos y lógicos de los Libros en línea , con más detalles en la publicación de mi blog Por qué los planes de consulta se ejecutan al revés . Este modelo de fila a la vez es esencial para formar una intuición sólida para la ejecución de consultas.

Mi pregunta es, ¿cómo (y por qué) una TOPcláusula n impacta el plan de ejecución de una consulta?

Algunas operaciones lógicas como TOP, semiuniones y la FAST n sugerencia de consulta afectan la forma en que el optimizador de consultas cuesta alternativas de plan de ejecución. La idea básica es que una posible forma de plan podría devolver las primeras n filas más rápidamente que un plan diferente que se optimizó para devolver todas las filas.

Por ejemplo, la unión de bucles anidados indexados es a menudo la forma más rápida de devolver una pequeña cantidad de filas, aunque la combinación hash o fusionada con escaneos puede ser más eficiente en conjuntos más grandes. La forma en que el optimizador de consultas razona sobre estas opciones es estableciendo un Objetivo de fila en un punto particular del árbol lógico de operaciones.

Un objetivo de fila modifica la forma en que se calculan las alternativas del plan de consulta. La esencia de esto es que el optimizador comienza costando a cada operador como si se requiriera el conjunto de resultados completo, establece un objetivo de fila en el punto apropiado y luego retrocede en el árbol del plan estimando el número de filas que espera examinar. para cumplir el objetivo de la fila.

Por ejemplo, un lógico TOP(10)establece un objetivo de fila de 10 en un punto particular del árbol de consulta lógica. Los costos de los operadores que conducen al objetivo de la fila se modifican para estimar cuántas filas necesitan producir para alcanzar el objetivo de la fila. Este cálculo puede volverse complejo, por lo que es más fácil entender todo esto con un ejemplo completamente trabajado y planes de ejecución anotados. Los objetivos de fila pueden afectar más que la elección del tipo de combinación o si las búsquedas y búsquedas son preferibles a los escaneos. Más detalles sobre eso aquí .

Como siempre, un plan de ejecución seleccionado en función de un objetivo de fila está sujeto a las capacidades de razonamiento del optimizador y a la calidad de la información que se le proporciona. No todos los planes con un objetivo de fila producirán el número requerido de filas más rápido en la práctica, pero de acuerdo con el modelo de costos lo hará.

Cuando un plan de objetivos de fila no sea más rápido, generalmente hay formas de modificar la consulta o proporcionar mejor información al optimizador de modo que el plan seleccionado de forma natural sea el mejor. La opción adecuada en su caso depende de los detalles, por supuesto. La función de objetivo de fila es generalmente muy efectiva (aunque hay un error a tener en cuenta cuando se usa en planes de ejecución paralelos).

Es posible que su consulta y plan en particular no sean adecuados para un análisis detallado aquí (de todos modos, proporcione un plan de ejecución real si lo desea), pero es de esperar que las ideas esbozadas aquí le permitan avanzar.

Paul White dice GoFundMonica
fuente
12

Cuando usa TOP, Optimizer ve la oportunidad de hacer menos trabajo. Si solicita 10 filas, entonces hay una buena posibilidad de que no necesite consumir todo el conjunto. Por lo tanto, el operador TOP puede ser empujado mucho más hacia la derecha. Seguirá solicitando filas al siguiente operador (a su derecha), hasta que haya recibido suficiente.

Señala que sin TOP, la consulta clasifica los datos al final. Si el motor pudiera saber cuántas filas iba a satisfacer la unión por adelantado, bien podría optar por utilizar un plan similar, colocando el TOP a la izquierda. Pero con el esfuerzo de hacer un Hash Match relativamente alto, y presumiblemente no hay opción para unir Merge Join, el Optimizador podría preferir filtrar el TOP más hacia la derecha.

Cuando se consulta la tabla B, se obtiene una sola fila a la vez. Es por eso que la estimación es 1. También supone que solo encontrará esa fila el 50% del tiempo. Entonces adivina que necesitará 2n + 1 busca encontrarlo.

Rob Farley
fuente
Eso no parece correcto que el número estimado de filas cambiaría en función de la forma en que se obtienen los datos. La forma en que obtiene los datos no debería afectar la cardinalidad. Un cambio en la forma en que se obtiene se reflejaría en el número de ejecuciones, ¿correcto?
David
El "número estimado de filas" es por ejecución. En un bucle anidado, es muy probable que se ejecute más de una vez.
Rob Farley
Este sería un comportamiento diferente al Número real de filas y al número (real) de ejecuciones en ese momento. Si el plan real muestra 16.834 ejecuciones reales y 15.407 filas reales devueltas, supongo que significa que realizó 16k búsquedas pero solo encontró 15k que coinciden con el predicado. Si significara 15k filas por ejecución, esto sería 15k * 16k = 240 millones de filas, aproximadamente 10 veces más grande que la tabla ...
David
Además, no estoy seguro de seguir la última declaración de su respuesta. Cuando dices que 2n + 1 busca "eso", ¿qué quieres decir con "eso"? ¿Seguramente no una sola fila? ¿Quiere decir que el optimizador supone que para cualquier fila dada en A hay un 50% de posibilidades de que coincida con B y, por lo tanto, tendrá que "probar" las filas 2003 de A para obtener 1001 coincidencias de B? ¿Microsoft documenta este comportamiento en alguna parte? ¿Y qué tiene que ver con la TOPcláusula? Gracias por su (s) respuesta (s) / paciencia.
David
Sí, las filas estimadas son por ejecución. Las filas reales son totales. Sin embargo, no hay ningún problema para que un operador devuelva más filas que las de la tabla, ya que es muy fácil demostrar que los operadores devuelven la misma fila varias veces.
Rob Farley