¿Cómo puedo deshacerme de una rama paralela inútil cuando se desconecta una sola fila?

9

Considere la siguiente consulta que desconecta algunos puñados de agregados escalares:

SELECT A, B
FROM (
    SELECT 
      MAX(CASE WHEN ID = 1 THEN 1 ELSE 0 END) VAL1
    , MAX(CASE WHEN ID = 2 THEN 1 ELSE 0 END) VAL2
    , MAX(CASE WHEN ID = 3 THEN 1 ELSE 0 END) VAL3
    , MAX(CASE WHEN ID = 4 THEN 1 ELSE 0 END) VAL4
    , MAX(CASE WHEN ID = 5 THEN 1 ELSE 0 END) VAL5
    , MAX(CASE WHEN ID = 6 THEN 1 ELSE 0 END) VAL6
    , MAX(CASE WHEN ID = 7 THEN 1 ELSE 0 END) VAL7
    , MAX(CASE WHEN ID = 16 THEN 1 ELSE 0 END) VAL16
    FROM dbo.PARALLEL_ZONE_REPRO
) q
UNPIVOT(B FOR A IN (
    VAL1
    ,VAL2
    ,VAL3
    ,VAL4
    ,VAL5
    ,VAL6
    ,VAL7
    ,VAL16
)) U
OPTION (MAXDOP 4);

En SQL Server 2017, obtengo un plan con dos ramas paralelas. La rama paralela izquierda se siente fuera de lugar para mí. El optimizador tiene la garantía de que solo habrá una salida de fila única desde el agregado escalar global, sin embargo, el operador principal es Distribute Streams con partición round robin:

round robin

Cuando ejecuto la consulta, todas las filas van a un solo hilo como se esperaba. No hay ningún problema de rendimiento con esta consulta, pero la consulta reserva 8 subprocesos paralelos con MAXDOP establecido en 4. Nuevamente, siento que esto está fuera de lugar. Es imposible que ambas ramas paralelas se ejecuten al mismo tiempo. Quiero evitar la reserva innecesaria de subprocesos de trabajo porque tengo habilitado TF 2467, que cambia el algoritmo de programación para ver la cantidad de subprocesos de trabajo por planificador.

¿Es posible reescribir la consulta para tener exactamente una rama paralela que contenga el escaneo de la tabla y el agregado local? Por ejemplo, estaría bien con la forma general a continuación, excepto que quiero que el bucle anidado se ejecute en una zona en serie:

ingrese la descripción de la imagen aquí

Para Application Reasons ™, prefiero evitar dividir esta consulta en partes. Si lo desea, puede ver el plan de consulta real aquí . Si desea jugar en casa, aquí está T-SQL para crear la tabla utilizada en la consulta:

DROP TABLE IF EXISTS dbo.PARALLEL_ZONE_REPRO;

CREATE TABLE dbo.PARALLEL_ZONE_REPRO (
    ID BIGINT,
    FILLER VARCHAR(100)
);

INSERT INTO dbo.PARALLEL_ZONE_REPRO WITH (TABLOCK)
SELECT
  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) % 15
, REPLICATE('Z', 100)
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
Joe Obbish
fuente

Respuestas:

8

Puedo obtener la forma de plan deseada con una unión de bucle en serie cuando se cumple todo lo siguiente:

  • Una APPLYo CROSS JOINse usa en lugar deUNPIVOT
  • El APPLYno contiene referencias externas
  • El origen de las filas en el APPLYes un constructor de valores de tabla en lugar de una tabla

Por ejemplo, aquí hay una forma de hacerlo:

SELECT A, B
FROM 
(
    SELECT A
    , MAX(
        CASE
            WHEN A = 'VAL1' THEN VAL1 
            WHEN A = 'VAL2' THEN VAL2
            WHEN A = 'VAL3' THEN VAL3
            WHEN A = 'VAL4' THEN VAL4
            WHEN A = 'VAL5' THEN VAL5
            WHEN A = 'VAL6' THEN VAL6
            WHEN A = 'VAL7' THEN VAL7
            WHEN A = 'VAL16' THEN VAL16
            ELSE NULL
        END
    ) B
    FROM (
         SELECT 
           MAX(CASE WHEN ID = 1 THEN 1 ELSE 0 END) VAL1
         , MAX(CASE WHEN ID = 2 THEN 1 ELSE 0 END) VAL2
         , MAX(CASE WHEN ID = 3 THEN 1 ELSE 0 END) VAL3
         , MAX(CASE WHEN ID = 4 THEN 1 ELSE 0 END) VAL4
         , MAX(CASE WHEN ID = 5 THEN 1 ELSE 0 END) VAL5
         , MAX(CASE WHEN ID = 6 THEN 1 ELSE 0 END) VAL6
         , MAX(CASE WHEN ID = 7 THEN 1 ELSE 0 END) VAL7
         , MAX(CASE WHEN ID = 16 THEN 1 ELSE 0 END) VAL16
         FROM dbo.PARALLEL_ZONE_REPRO
    ) q
    CROSS APPLY (
        VALUES ('VAL1'), ('VAL2'), ('VAL3'), ('VAL4'),
        ('VAL5'), ('VAL6'), ('VAL7'), ('VAL16') 
    ) ca (A)
    GROUP BY A
) q
WHERE q.B IS NOT NULL
OPTION (MAXDOP 4);

Obtengo la forma de plan deseada como se afirma con solo una rama paralela:

ingrese la descripción de la imagen aquí

Intenté muchas otras cosas que no funcionaron. Esta respuesta no es satisfactoria porque no sé por qué funciona y puede que no funcione en una versión futura de SQL Server, pero resolvió mi problema.

Joe Obbish
fuente
8

Es imposible que ambas ramas paralelas se ejecuten al mismo tiempo.

La ejecución comienza en el borde izquierdo del plan. La rama de bucles anidados se está ejecutando (abriendo, esperando datos) cuando se está ejecutando la rama de exploración de tabla. Esto es inevitable . Ambas sucursales están activas al mismo tiempo, por lo que SQL Server reservará 2 * trabajadores DOP para este plan.

Para una solución robusta, puede colocar el pivote en una función con valores de tabla:

CREATE OR ALTER FUNCTION dbo.PivotPZR()
RETURNS @R table 
(
    VAL1 bigint NOT NULL, VAL2 bigint NOT NULL,
    VAL3 bigint NOT NULL, VAL4 bigint NOT NULL,
    VAL5 bigint NOT NULL, VAL6 bigint NOT NULL,
    VAL7 bigint NOT NULL, VAL16 bigint NOT NULL
)
WITH SCHEMABINDING AS
BEGIN
    DECLARE 
        @Val1 bigint, @Val2 bigint, @Val3 bigint, @Val4 bigint,
        @Val5 bigint, @Val6 bigint, @Val7 bigint, @Val16 bigint;

    -- Can use parallelism
    SELECT
        @Val1 = MAX(CASE WHEN PZR.ID = 1 THEN 1 ELSE 0 END),
        @Val2 = MAX(CASE WHEN PZR.ID = 2 THEN 1 ELSE 0 END),
        @Val3 = MAX(CASE WHEN PZR.ID = 3 THEN 1 ELSE 0 END),
        @Val4 = MAX(CASE WHEN PZR.ID = 4 THEN 1 ELSE 0 END),
        @Val5 = MAX(CASE WHEN PZR.ID = 5 THEN 1 ELSE 0 END),
        @Val6 = MAX(CASE WHEN PZR.ID = 6 THEN 1 ELSE 0 END),
        @Val7 = MAX(CASE WHEN PZR.ID = 7 THEN 1 ELSE 0 END),
        @Val16 = MAX(CASE WHEN PZR.ID = 16 THEN 1 ELSE 0 END)
    FROM dbo.PARALLEL_ZONE_REPRO AS PZR;

    -- Single result row
    INSERT @R
        (VAL1, VAL2, VAL3, VAL4, VAL5, VAL6, VAL7, VAL16)
    VALUES
        (@Val1, @Val2, @Val3, @Val4, @Val5, @Val6, @Val7, @Val16);

    RETURN;
END;

Luego reescribe la consulta como:

SELECT
    U.A,
    U.B
FROM dbo.PivotPZR() AS PP
UNPIVOT
(
    B FOR A IN (VAL1, VAL2 ,VAL3 ,VAL4, VAL5 ,VAL6 ,VAL7 ,VAL16)
) AS U;

La función usa paralelismo con una sola rama como se desee:

Plan de funciones

El plan de ejecución de nivel superior es:

Consulta de nivel superior

Paul White 9
fuente