¿Por qué hacer referencia a una variable en un predicado de unión fuerza bucles anidados?

16

Me encontré con este problema recientemente y no pude encontrar ninguna discusión en línea.

La consulta a continuación

DECLARE @S VARCHAR(1) = '';

WITH T
     AS (SELECT name + @S AS name2,
                *
         FROM   master..spt_values)
SELECT *
FROM   T T1
       INNER JOIN T T2
         ON T1.name2 = T2.name2;

Siempre obtiene un plan de bucles anidados

ingrese la descripción de la imagen aquí

Intentar forzar el problema con INNER HASH JOINo INNER MERGE JOINpistas produce el siguiente error.

El procesador de consultas no pudo generar un plan de consulta debido a las sugerencias definidas en esta consulta. Vuelva a enviar la consulta sin especificar ninguna sugerencia y sin usar SET FORCEPLAN.

Encontré una solución alternativa que permite el uso de combinaciones hash o de fusión, envolviendo la variable en un agregado. El plan generado tiene un costo significativamente menor (19.2025 vs 0.261987)

DECLARE @S2 VARCHAR(1) = '';

WITH T
     AS (SELECT name + (SELECT MAX(@S2)) AS name2,
                *
         FROM   spt_values)
SELECT *
FROM   T T1
       INNER JOIN T T2
         ON T1.name2 = T2.name2; 

ingrese la descripción de la imagen aquí

¿Cuál es la razón de este comportamiento? y hay una mejor solución que la que encontré? (que tal vez no requiere las ramas adicionales del plan de ejecución)

Martin Smith
fuente

Respuestas:

13

He intentado su consulta en una instancia de SQL 2012 y el indicador de seguimiento 4199 parece solucionar el problema. Con esto habilitado, obtengo una combinación de fusión por un costo total de 0.24 y ninguna de las ramas adicionales.

El artículo específico de KB para este problema es Problemas de rendimiento que ocurren cuando el predicado de unión en su consulta tiene columnas de referencia externas en SQL Server 2005 o en SQL Server 2008

ingrese la descripción de la imagen aquí

Para calificar aún más, TF 4199 habilita todas las correcciones del optimizador. Vea este enlace para más información. Habilitar todo a la vez puede tener efectos secundarios extraños, por lo que si puede encontrar una solución específica, podría ser mejor habilitar la solución por sí solo.

Puede habilitar un indicador de rastreo por consulta utilizando OPTION (QUERYTRACEON 4199);

Tom V - Equipo Mónica
fuente
0

Antigua pregunta, pero al ver la respuesta no era súper definitiva, pensé que publicaría una solución que encontré. No estoy seguro de por qué el optimizador de consultas se resiste HASH, pero creo que no le gusta MERGEporque no tiene una entrada ordenada. El 14 de diciembre de 2012

DECLARE @S VARCHAR(1) = '';

    WITH T
        AS (SELECT TOP (2147483647)
                name + @S AS name2,
                *
            FROM   master..spt_values
            ORDER BY name + @S)
    SELECT *
    FROM   T T1
           INNER JOIN T T2
             ON T1.name2 = T2.name2;

produce el siguiente plan:

ingrese la descripción de la imagen aquí

Forzar TOPy ORDER BYen el cte parece dar al optimizador suficiente conocimiento sobre el conjunto de datos para realizar el MERGE JOIN.

VBlades
fuente