并行查询示例
以下查询计算指定季度(自 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
假定对 lineitem 和 order 表定义了下列索引:
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)
上图显示按并行度等于 4 执行且包括一个双表联接的查询优化器计划。
这个并行计划包含三个并行运算符。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 运算符进行输入排序。与 Merge Join 运算符一样,Sort 运算符也是并行执行的。
最上面的 Parallelism 运算符将若干流的结果收集成一个流。之后,该 Parallelism 运算符下方的 Stream Aggregate 运算符所执行的部分聚合被聚集到单个的 SUM 值中,这个 SUM 值是该 Parallelism 运算符上方的 Stream Aggregate 运算符中每个不同的 O_ORDERPRIORITY 值之和。因为此计划有两个交换部分,且并行度等于 4,所以它使用了八个线程。