並列クエリの例

次のクエリでは、2000 年 4 月 1 日を開始日とする特定の四半期に受けた注文のうち、納品期日を過ぎた項目を 1 つ以上含む注文の件数を数えます。さらに、該当する注文を受注優先度別にグループ分けし、受注優先度の昇順に並べ替えてその注文数を一覧表示します。

この例には、架空のテーブル名と列名を使用しています。

SELECT o_orderpriority, COUNT(*) AS Order_Count
FROM orders
WHERE o_orderdate >= '2000/04/01'
   AND o_orderdate < DATEADD (mm, 3, '2000/04/01')
   AND EXISTS
         (
          SELECT *
            FROM    lineitem
            WHERE l_orderkey = o_orderkey
               AND l_commitdate < l_receiptdate
         )
   GROUP BY o_orderpriority
   ORDER BY o_orderpriority

lineitem テーブルと orders テーブルで次のインデックスが定義されていると想定します。

CREATE INDEX l_order_dates_idx 
   ON lineitem
      (l_orderkey, l_receiptdate, l_commitdate, l_shipdate)

CREATE UNIQUE INDEX o_datkeyopr_idx
   ON ORDERS
      (o_orderdate, o_orderkey, o_custkey, o_orderpriority)

上記のクエリに対して生成される並列プランの例を次に示します。

|--Stream Aggregate(GROUP BY:([ORDERS].[o_orderpriority])
                  DEFINE:([Expr1005]=COUNT(*)))
    |--Parallelism(Gather Streams, ORDER BY:
                  ([ORDERS].[o_orderpriority] ASC))
         |--Stream Aggregate(GROUP BY:
                  ([ORDERS].[o_orderpriority])
                  DEFINE:([Expr1005]=Count(*)))
              |--Sort(ORDER BY:([ORDERS].[o_orderpriority] ASC))
                   |--Merge Join(Left Semi Join, MERGE:
                  ([ORDERS].[o_orderkey])=
                        ([LINEITEM].[l_orderkey]),
                  RESIDUAL:([ORDERS].[o_orderkey]=
                        [LINEITEM].[l_orderkey]))
                        |--Sort(ORDER BY:([ORDERS].[o_orderkey] ASC))
                        |    |--Parallelism(Repartition Streams,
                           PARTITION COLUMNS:
                           ([ORDERS].[o_orderkey]))
                        |         |--Index Seek(OBJECT:
                     ([tpcd1G].[dbo].[ORDERS].[O_DATKEYOPR_IDX]),
                     SEEK:([ORDERS].[o_orderdate] >=
                           Apr  1 2000 12:00AM AND
                           [ORDERS].[o_orderdate] <
                           Jul  1 2000 12:00AM) ORDERED)
                        |--Parallelism(Repartition Streams,
                     PARTITION COLUMNS:
                     ([LINEITEM].[l_orderkey]),
                     ORDER BY:([LINEITEM].[l_orderkey] ASC))
                             |--Filter(WHERE:
                           ([LINEITEM].[l_commitdate]<
                           [LINEITEM].[l_receiptdate]))
                                  |--Index Scan(OBJECT:
         ([tpcd1G].[dbo].[LINEITEM].[L_ORDER_DATES_IDX]), ORDERED)

2 つのテーブルが結合されたクエリ プラン

この図は、並列処理の次数が 4 で実行され、2 つのテーブルが結合されているクエリ オプティマイザのプランを示しています。

並列プランには、3 つの並列処理操作が含まれています。o_datkey_ptr インデックスの Index Seek 操作と l_order_dates_idx インデックスの Index Scan 操作が並列に実行されます。これにより、複数の排他ストリームが生成されます。この処理は、Index Scan 操作と Index Seek 操作の上位にあり最も近い Parallelism 操作からそれぞれ決定できます。どちらの操作もストリームを再分割し、交換の種類を決定しています。つまり、単にストリーム間でデータを再移動して、入力時と同じ数のストリームを出力時に生成しているということです。このストリーム数は並列処理の次数と同じになります。

l_order_dates_idxIndex Scan 操作の上位にある Parallelism 操作は、L_ORDERKEY の値をキーとして使用して、入力ストリームを再分割しています。このようにして、同じ L_ORDERKEY の値が同じ出力ストリームで終了します。同時に、出力ストリームは L_ORDERKEY 列の順序を維持し、Merge Join 操作の入力要件を満たします。

Index Seek 操作の上位にある Parallelism 操作は、O_ORDERKEY の値を使用して入力ストリームを再分割します。この入力は O_ORDERKEY 列の値で並べ替えられておらず、Merge Join 操作の結合列でもあるので、Parallelism 操作と Merge Join 操作の間の Sort 操作は、入力が Merge Join 操作のために結合列で並べ替えられることを保証しています。Sort 操作は、Merge Join 操作と同様に並列処理されます。

最上位にある Parallelism 操作は、複数のストリームから得た結果を 1 つのストリームに集めます。この Parallelism 操作の下位にある Stream Aggregate 操作で実行された部分集計は、Parallelism 操作の上位にある Stream Aggregate 操作の O_ORDERPRIORITY の異なる値ごとに 1 つの SUM 値に累計されます。このプランには並列処理の次数が 4 に設定された 2 つの交換セグメントが含まれているため、8 個のスレッドが使用されます。

関連項目

概念