并行查询示例

以下查询计算指定季度(自 2000 年 4 月 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

假定对 lineitemorder 表定义了下列索引:

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)

具有 DOP 4 的查询计划,涉及双表联接

上图显示按并行度等于 4 执行且包括一个双表联接的查询优化器计划。

这个并行计划包含三个并行运算符。o_datkey_ptr 索引的 Index Seek 运算符和 l_order_dates_idx 索引的 Index Scan 运算符是并行执行的。将生成若干排他流。这可以分别通过 Index ScanIndex 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 运算符中的联接列,ParallelismMerge Join 运算符之间的 Sort 运算符确保为联接列的 Merge Join 运算符进行输入排序。与 Merge Join 运算符一样,Sort 运算符也是并行执行的。

最上面的 Parallelism 运算符将若干流的结果收集成一个流。之后,该 Parallelism 运算符下方的 Stream Aggregate 运算符所执行的部分聚合被聚集到单个的 SUM 值中,这个 SUM 值是该 Parallelism 运算符上方的 Stream Aggregate 运算符中每个不同的 O_ORDERPRIORITY 值之和。因为此计划有两个交换部分,且并行度等于 4,所以它使用了八个线程。

请参阅

概念