Рассмотрим следующий запрос, который разворачивает несколько горстей скалярных агрегатов:
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, который изменяет алгоритм планирования, чтобы посмотреть количество рабочих потоков на планировщик.
Можно ли переписать запрос так, чтобы он имел ровно одну параллельную ветвь, содержащую сканирование таблицы и локальный агрегат? Например, я буду в порядке с общей формой ниже, за исключением того, что я хочу, чтобы вложенный цикл выполнялся в последовательной зоне:
Для Application Reasons ™ я настоятельно предпочитаю не разбивать этот запрос на части. При желании вы можете просмотреть актуальный план запроса здесь . Если вы хотите поиграть дома, вот 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;