少数のスカラー集計をアンピボットする次のクエリを考えてみます。
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で、2つの並列ブランチを持つプランを取得します。左の平行枝は私には場違いだと感じます。オプティマイザーは、グローバルスカラー集約からの単一の行出力のみが存在することを保証しますが、その親オペレーターはラウンドロビンパーティション化を使用した分散ストリームです。
クエリを実行すると、期待どおりにすべての行が1つのスレッドに移動します。このクエリにはパフォーマンスの問題はありませんが、クエリはMAXDOPが4に設定された8つの並列スレッドを予約しています。繰り返しますが、これは適切ではないと感じています。両方の並列ブランチを同時に実行することは不可能です。TF 2467を有効にして、スケジューリングアルゴリズムを変更し、スケジューラごとのワーカースレッドの数を調べるため、不要なワーカースレッドの予約を回避したいと思います。
クエリを書き換えて、テーブルスキャンとローカル集計を含む並列ブランチを1つだけにすることはできますか?たとえば、ネストされたループをシリアルゾーンで実行することを除いて、以下の一般的な形状で問題ありません。
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;