¿Por qué cambian las estimaciones de fila de SQL Server cuando agrego una sugerencia de combinación?

15

Tengo una consulta que une algunas tablas y funciona bastante mal: las estimaciones de fila están muy lejos (1000 veces) y se elige la unión de bucles anidados, lo que da como resultado múltiples escaneos de tabla. La forma de la consulta es bastante sencilla, se parece a esto:

SELECT t1.id
FROM t1
INNER JOIN t2 ON t1.id = t2.t1_id
LEFT OUTER JOIN t3 ON t2.id = t3.t2_id
LEFT OUTER JOIN t4 ON t3.t4_id = t4.id 
WHERE t4.id = some_GUID

Jugando con la consulta, noté que cuando le sugiero que use una combinación de combinación para una de las combinaciones, se ejecuta muchas veces más rápido. Esto lo puedo entender: la combinación de combinación es una mejor opción para los datos que se unen, pero SQL Server simplemente no estima que es correcto elegir los bucles anidados.

Lo que no entiendo completamente es por qué esta sugerencia de combinación cambia todas las estimaciones para todos los operadores del plan. Al leer diferentes artículos y libros, asumí que las estimaciones de cardinalidad se realizan antes de que se construya el plan, por lo que el uso de una sugerencia no habría cambiado las estimaciones, sino que explícitamente le dijera a SQL Server que use una implementación de unión física particular.

Sin embargo, lo que veo es que la sugerencia de combinación hace que todas las estimaciones se vuelvan prácticamente perfectas. ¿Por qué sucede esto? ¿Existen técnicas comunes para hacer que el optimizador de consultas haga una mejor estimación sin una sugerencia, teniendo en cuenta que las estadísticas obviamente lo permiten?

UPD: los planes de ejecución anónimos se pueden encontrar aquí: https://www.dropbox.com/s/hchfuru35qqj89s/merge_join.sqlplan?dl=0 https://www.dropbox.com/s/38sjtv0t7vjjfdp/no_hints_join.sqlplan?dl = 0

Verifiqué las estadísticas utilizadas por ambas consultas usando TF 3604, 9292 y 9204, y son idénticas. Sin embargo, los índices que se escanean / buscan difieren entre las consultas.

Además de eso, intenté ejecutar la consulta con OPTION (FORCE ORDER): se ejecuta incluso más rápido que con la combinación de combinación, eligiendo HASH MATCH para cada combinación.

Alexander Shelemin
fuente
3
¿Te has dado cuenta de que tienes una combinación externa pero estás usando la tabla en la cláusula where?
James Z
@JamesZ: sí, soy consciente de eso, aunque no creo que haya un problema con eso.
Alexander Shelemin
99
@AlexSh Bueno, hay un problema lógico / semántico con eso, porque eso cambia su combinación externa a una interna.
Aaron Bertrand

Respuestas:

21

Al leer diferentes artículos y libros, asumí que las estimaciones de cardinalidad se realizan antes de construir el plan.

No exactamente. Se deriva una estimación de cardinalidad inicial (después de las simplificaciones y otros trabajos), que influye en el orden de unión inicial elegido por el optimizador.

Sin embargo, las exploraciones posteriores (durante la optimización basada en costos) pueden, y a menudo lo hacen, dar como resultado que se calculen nuevas estimaciones de cardinalidad. Estas CE posteriores pueden ser más o menos "precisas". Si se produce una subestimación, el optimizador puede elegir un plan que parezca más barato, pero que de hecho se ejecute por mucho más tiempo.

En general, no hay garantía de que las estimaciones de cardinalidad para subárboles semánticamente idénticos produzcan los mismos resultados. Es un proceso estadístico, después de todo, y algunas operaciones tienen un respaldo CE más profundo que otras.

En su caso, parece haber otro factor: el optimizador introduce (o se mueve) un Top, que establece un objetivo de fila en el subárbol debajo de él:

Fragmento de plan

Si habilitara el indicador de seguimiento 4138 (en 2008 R2 o posterior), puede encontrar las estimaciones más en línea con las expectativas, o tal vez incluso que el optimizador ya no elegiría bucles anidados.

Sin embargo, lo que veo es que la sugerencia de combinación hace que todas las estimaciones se vuelvan prácticamente perfectas.

Hay un elemento de suerte involucrado aquí. Las personas tienden a escribir consultas, o al menos las uniones, en el orden en que esperan que se realicen físicamente. El uso de una sugerencia de combinación viene implícito FORCE ORDER, lo que soluciona el orden de combinación para que coincida con la forma textual y desactiva muchas reglas de exploración del optimizador que pueden conducir a una nueva estimación de la cardinalidad.

Además de eso, intenté ejecutar la consulta con OPTION (FORCE ORDER): se ejecuta incluso más rápido que con la combinación de combinación, eligiendo HASH MATCH para cada combinación.

Esto es lo mismo que insinuar una unión, pero no restringe la elección del operador de unión física. Una vez más, si escribiste el orden de unión de la consulta de una manera lógica, es muy probable que obtengas un plan razonable. Por supuesto, de esta manera se pierden muchas de las habilidades del optimizador, lo que puede no producir resultados óptimos en situaciones más generales.

Probablemente no quiera usarlo FORCE ORDERmuy a menudo porque es una sugerencia (directiva) extremadamente poderosa que tiene efectos más amplios que el simple forzar el orden de las uniones; por ejemplo, evita que el optimizador mueva los agregados e introduzca agregaciones parciales. Aconsejo mucho no usar esta sugerencia, excepto en circunstancias muy excepcionales y por sintonizadores verdaderamente expertos .

Un análisis detallado requeriría más tiempo del que tengo ahora, y acceso a una copia de la base de datos solo para estadísticas.

Paul White reinstala a Monica
fuente
-10

El donde niega la izquierda
¿Por qué dificultar el optimizador?
En 3 o más uniones, el optimizador TENDRÁ a ponerse a la defensiva y en uniones en bucle, ya que eso protege la memoria
. sigue siendo una realidad
Con múltiples combinaciones, extraiga las condiciones desde el lugar hacia la combinación cuando pueda

SELECT t1.id
  FROM t1
  JOIN t2 
        ON t1.id = t2.t1_id
  JOIN t3 
        ON t2.id = t3.t2_id
  JOIN t4 
        ON t3.t4_id = t4.id 
       AND t4.id = some_GUID 

O incluso mejor aún: apuesto a que esto cumplirá o superará tus pistas o fuerza

SELECT t1.id
  FROM t1
  JOIN t2 
        ON t1.id = t2.t1_id
  JOIN t3 
        ON t2.id = t3.t2_id
       AND t3.t4_id = some_GUID

El problema con las sugerencias es que son para datos en un estado específico. Escriba una consulta limpia y deje que el optimizador haga su trabajo. Algunas veces solo necesita más estadísticas para hacer lo correcto, pero luego se bloqueará.

Por qué diferentes estimaciones. A planes diferentes. Comience con consultas que le den al optimizador una oportunidad de pelear.

paparazzo
fuente