Rozważ następujące zapytanie, które rozdziela kilka garstek agregatów skalarnych:
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);
Na SQL Server 2017 otrzymuję plan z dwoma równoległymi gałęziami. Lewa równoległa gałąź wydaje mi się nie na miejscu. Optymalizator ma gwarancję, że globalny agregat skalarny będzie generował tylko jeden wiersz, ale jego operatorem nadrzędnym jest dystrybucja strumieni z partycjonowaniem okrągłym:
Kiedy wykonuję zapytanie, wszystkie wiersze przechodzą do jednego wątku zgodnie z oczekiwaniami. Z tym zapytaniem nie ma problemu z wydajnością, ale zapytanie rezerwuje 8 równoległych wątków z MAXDOP ustawionym na 4. Ponownie czuję, że to nie na miejscu. Niemożliwe jest jednoczesne wykonanie obu równoległych gałęzi. Chcę uniknąć niepotrzebnej rezerwacji wątków roboczych, ponieważ mam włączony TF 2467, który zmienia algorytm szeregowania, aby sprawdzić liczbę wątków roboczych na harmonogram.
Czy możliwe jest przepisanie zapytania, tak aby zawierało dokładnie jedną gałąź równoległą, która zawiera skanowanie tabeli i lokalną agregację? Na przykład byłbym w porządku z ogólnym kształtem poniżej, z tym wyjątkiem, że chcę, aby zagnieżdżona pętla była wykonywana w strefie szeregowej:
W przypadku powodów związanych z aplikacją zdecydowanie wolę unikać dzielenia tego zapytania na części. W razie potrzeby możesz wyświetlić aktualny plan zapytań tutaj . Jeśli chcesz grać razem w domu, oto T-SQL do utworzenia tabeli używanej w zapytaniu:
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;
źródło