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?
EXCEPT
(por ejemplo OUTER 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.