Considérez la requête suivante qui détourne quelques poignées d'agrégats scalaires:
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);
Sur SQL Server 2017, j'obtiens un plan avec deux branches parallèles. La branche parallèle gauche me semble hors de propos. L'optimiseur a la garantie qu'il n'y aura qu'une seule sortie de ligne de l'agrégat scalaire global, mais l'opérateur parent de celui-ci est un flux de distribution avec partitionnement à tour de rôle:
Lorsque j'exécute la requête, toutes les lignes vont à un seul thread comme prévu. Il n'y a pas de problème de performances avec cette requête, mais la requête réserve 8 threads parallèles avec MAXDOP défini sur 4. Encore une fois, je pense que cela est hors de propos. Il est impossible pour les deux branches parallèles de s'exécuter en même temps. Je veux éviter la réservation inutile de threads de travail, car j'ai activé TF 2467, ce qui modifie l'algorithme de planification pour examiner le nombre de threads de travail par planificateur.
Est-il possible de réécrire la requête pour avoir exactement une branche parallèle contenant l'analyse de table et l'agrégat local? Par exemple, je serais bien avec la forme générale ci-dessous, sauf que je veux que la boucle imbriquée s'exécute dans une zone série:
Pour Application Reasons ™, je préfère fortement éviter de diviser cette requête en plusieurs parties. Si vous le souhaitez, vous pouvez afficher le plan de requête réel ici . Si vous souhaitez jouer à la maison, voici T-SQL pour créer la table utilisée dans la requête:
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;
la source