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:
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:
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;
fuente