Rompecabezas optimizador de consultas de SQL Server 2008 R2
Tenemos dos tablas, ambas con 9 millones de filas. 70,000 filas son diferentes, las otras son iguales.
Esto es rápido, 13 segundos,
select * from bigtable1
except select * from similar_bigtable2
Esto ordena la salida y también es rápido, 13 segundos también,
select * into #q from bigtable1
except select * from similar_bigtable2
select * from #q order by sort_column
Si bien esto es enormemente lento:
;with q as (
select * from bigtable1
except select * from similar_bigtable2
)
select * from q order by sort_column
E incluso un "truco" que a veces utilizo para insinuar que SQL Server necesita calcular previamente una cierta parte de la consulta antes de continuar, no funciona y resulta en una consulta lenta también:
;with q as (
select top 100 percent * from bigtable1
except select * from similar_bigtable2
)
select * from q order by sort_column
Mirando los planes de consulta, no es difícil encontrar el motivo:
SQL Server coloca dos tipos de 9 millones de filas antes del hashmatch, mientras que preferiría que hubiera agregado solo un tipo de 70,000 filas después del hashmatch.
Entonces, la pregunta: ¿cómo puedo indicarle al optimizador de consultas que haga eso?
fuente
EXCEPT
(por ejemploOUTER JOIN
)? Me doy cuenta de que la sintaxis es menos conveniente, pero es posible que pueda jugar con pistas de índice / unión mejor allí (o puede que no sea necesario). La alternativa que está usando ahora (primero en una tabla #temp) es una solución alternativa de último recurso, pero en algunos casos es la única forma de forzar al optimizador a separar por completo dos partes de una consulta de la manera que desee.Respuestas:
La principal diferencia entre estos dos planes de consulta es, de hecho, la diferencia de Hash Match y Merge Join. Hash Match es más eficiente y, como puede ver, la consulta se ejecuta más rápido en la opción 1 (sin usar CTE).
CTE es una gran herramienta, pero parece no ser eficiente en dos casos, Predicados complejos o Clave principal / secundaria no única. En su caso, no hay una clave única y el servidor SQL debe ordenar primero los conjuntos de datos para poder cumplir con sus requisitos. Eche un vistazo al siguiente enlace que le brinda más información sobre este tema: http://blogs.msdn.com/b/sqlcat/archive/2011/04/28/optimize-recursive-cte-query.aspx
Por lo tanto, parece que debe aceptar su lentitud o reescribir la lógica con el ciclo WHILE, que puede ser más eficiente.
fuente
Intenta esto, ¿algo mejor?
fuente
Esta no es una solución ideal, pero si no puede estructurar el tsql para generar un plan eficiente, puede establecer una guía de plan para forzar el plan que desea. Hacer esto significaría que si un plan más eficiente está disponible, SQL no lo considerará, pero es una opción.
fuente