Как я могу избавиться от бесполезной параллельной ветки при отмене поворота одной строки?


9

Рассмотрим следующий запрос, который разворачивает несколько горстей скалярных агрегатов:

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;

Ответы:


8

Я могу получить желаемую форму плана с помощью соединения последовательного цикла, когда выполняются все следующие условия:

  • APPLYИли CROSS JOINиспользуется вместоUNPIVOT
  • Не APPLYсодержит внешних ссылок
  • Источник строк в APPLYконструкторе табличных значений в отличие от таблицы

Например, вот один из способов сделать это:

SELECT A, B
FROM 
(
    SELECT A
    , MAX(
        CASE
            WHEN A = 'VAL1' THEN VAL1 
            WHEN A = 'VAL2' THEN VAL2
            WHEN A = 'VAL3' THEN VAL3
            WHEN A = 'VAL4' THEN VAL4
            WHEN A = 'VAL5' THEN VAL5
            WHEN A = 'VAL6' THEN VAL6
            WHEN A = 'VAL7' THEN VAL7
            WHEN A = 'VAL16' THEN VAL16
            ELSE NULL
        END
    ) 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
    CROSS APPLY (
        VALUES ('VAL1'), ('VAL2'), ('VAL3'), ('VAL4'),
        ('VAL5'), ('VAL6'), ('VAL7'), ('VAL16') 
    ) ca (A)
    GROUP BY A
) q
WHERE q.B IS NOT NULL
OPTION (MAXDOP 4);

Я получаю желаемую форму плана плана, как утверждается, только с одной параллельной ветвью:

введите описание изображения здесь

Я пробовал много других вещей, которые не работали. Этот ответ является неудовлетворительным, поскольку я не знаю, почему он работает, и он может не работать в будущей версии SQL Server, но он действительно решил мою проблему.


8

Невозможно выполнить обе параллельные ветви одновременно.

Выполнение начинается с левого края плана. Ветвь вложенных циклов работает (открытие, ожидание данных), когда работает ветвь сканирования таблицы. Это неизбежно . Обе ветви активны одновременно, поэтому SQL Server зарезервирует 2 * DOP работников для этого плана.

Для надежного решения вы можете поместить сводную таблицу в табличную функцию:

CREATE OR ALTER FUNCTION dbo.PivotPZR()
RETURNS @R table 
(
    VAL1 bigint NOT NULL, VAL2 bigint NOT NULL,
    VAL3 bigint NOT NULL, VAL4 bigint NOT NULL,
    VAL5 bigint NOT NULL, VAL6 bigint NOT NULL,
    VAL7 bigint NOT NULL, VAL16 bigint NOT NULL
)
WITH SCHEMABINDING AS
BEGIN
    DECLARE 
        @Val1 bigint, @Val2 bigint, @Val3 bigint, @Val4 bigint,
        @Val5 bigint, @Val6 bigint, @Val7 bigint, @Val16 bigint;

    -- Can use parallelism
    SELECT
        @Val1 = MAX(CASE WHEN PZR.ID = 1 THEN 1 ELSE 0 END),
        @Val2 = MAX(CASE WHEN PZR.ID = 2 THEN 1 ELSE 0 END),
        @Val3 = MAX(CASE WHEN PZR.ID = 3 THEN 1 ELSE 0 END),
        @Val4 = MAX(CASE WHEN PZR.ID = 4 THEN 1 ELSE 0 END),
        @Val5 = MAX(CASE WHEN PZR.ID = 5 THEN 1 ELSE 0 END),
        @Val6 = MAX(CASE WHEN PZR.ID = 6 THEN 1 ELSE 0 END),
        @Val7 = MAX(CASE WHEN PZR.ID = 7 THEN 1 ELSE 0 END),
        @Val16 = MAX(CASE WHEN PZR.ID = 16 THEN 1 ELSE 0 END)
    FROM dbo.PARALLEL_ZONE_REPRO AS PZR;

    -- Single result row
    INSERT @R
        (VAL1, VAL2, VAL3, VAL4, VAL5, VAL6, VAL7, VAL16)
    VALUES
        (@Val1, @Val2, @Val3, @Val4, @Val5, @Val6, @Val7, @Val16);

    RETURN;
END;

Затем перепишите запрос как:

SELECT
    U.A,
    U.B
FROM dbo.PivotPZR() AS PP
UNPIVOT
(
    B FOR A IN (VAL1, VAL2 ,VAL3 ,VAL4, VAL5 ,VAL6 ,VAL7 ,VAL16)
) AS U;

Функция использует параллелизм с одной веткой по желанию:

Функциональный план

План выполнения верхнего уровня:

Запрос верхнего уровня

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.