Як я можу позбутися непомітної паралельної гілки при невідвороті одного рядка?


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, який змінює алгоритм планування, щоб переглянути кількість робочих ниток на планувальника.

Чи можливо переписати запит, щоб мати рівно одну паралельну гілку, яка містить сканування таблиці та локальний агрегат? Наприклад, мені було б добре із загальною формою нижче, за винятком того, що я хочу, щоб вкладений цикл виконувався в послідовній зоні:

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

Для причин застосування ™ я настійно вважаю за краще уникати поділу цього запиту на частини. При бажанні ви можете переглянути фактичний план запитів тут . Якщо ви хочете пограти вдома, ось 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.