Розглянемо наступний запит, який демонструє кілька жмень скалярних агрегатів:
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);
На SQL Server 2017 я отримую план з двома паралельними гілками. Ліва паралельна гілка мені не відповідає. Оптимізатор має гарантію, що з глобального скалярного сукупності вийде лише один рядок, проте основним його оператором є розподілити потоки з круглим розділенням роботів:
Коли я виконую запит, всі рядки переходять до однієї нитки, як очікувалося. У цьому запиті немає проблем з продуктивністю, але запит залишає 8 паралельних потоків з MAXDOP, встановленими на 4. Знову я відчуваю, що це не на місці. Неможливо одночасно виконати обидві паралельні гілки. Я хочу уникнути зайвого резервування робочих потоків, тому що ввімкнено TF 2467, який змінює алгоритм планування, щоб переглянути кількість робочих ниток на планувальника.
Чи можливо переписати запит, щоб мати рівно одну паралельну гілку, яка містить сканування таблиці та локальний агрегат? Наприклад, мені було б добре із загальною формою нижче, за винятком того, що я хочу, щоб вкладений цикл виконувався в послідовній зоні:
Для причин застосування ™ я настійно вважаю за краще уникати поділу цього запиту на частини. При бажанні ви можете переглянути фактичний план запитів тут . Якщо ви хочете пограти вдома, ось T-SQL для створення таблиці, яка використовується в запиті:
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;