Betrachten Sie die folgende Abfrage, mit der einige Handvoll skalarer Aggregate entfernt werden:
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);
Unter SQL Server 2017 erhalte ich einen Plan mit zwei parallelen Zweigen. Der linke Parallelast fühlt sich für mich fehl am Platz an. Der Optimierer hat die Garantie, dass nur eine einzige Zeile vom globalen Skalaraggregat ausgegeben wird. Der übergeordnete Operator davon ist jedoch ein Distribute Streams mit Round-Robin-Partitionierung:
Wenn ich die Abfrage ausführe, gehen alle Zeilen wie erwartet zu einem einzelnen Thread. Es gibt kein Leistungsproblem mit dieser Abfrage, aber die Abfrage reserviert 8 parallele Threads mit MAXDOP auf 4. Auch hier bin ich der Meinung, dass dies nicht am richtigen Ort ist. Es ist unmöglich, dass beide parallelen Zweige gleichzeitig ausgeführt werden. Ich möchte unnötige Reservierungen von Arbeitsthreads vermeiden, da TF 2467 aktiviert ist, wodurch der Planungsalgorithmus geändert wird, um die Anzahl der Arbeitsthreads pro Planer anzuzeigen.
Ist es möglich, die Abfrage so umzuschreiben, dass genau ein paralleler Zweig vorhanden ist, der den Tabellenscan und das lokale Aggregat enthält? Zum Beispiel würde ich mit der folgenden allgemeinen Form gut zurechtkommen, außer dass ich möchte, dass die verschachtelte Schleife in einer seriellen Zone ausgeführt wird:
Aus Anwendungsgründen ™ bevorzuge ich dringend, diese Abfrage nicht in Teile aufzuteilen. Auf Wunsch können Sie hier den aktuellen Abfrageplan anzeigen . Wenn Sie zu Hause mitspielen möchten, finden Sie hier T-SQL, um die in der Abfrage verwendete Tabelle zu erstellen:
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;