平行查詢範例
下列查詢會計算從 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 和 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)
上圖所示為使用平行處理原則程度 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 運算子為輸入進行排序。Sort 運算子 (如 Merge Join 運算子) 會以平行方式執行。
最頂端的 Parallelism 運算子會將數個資料流中的結果,集合成單一資料流。接著,在 Parallelism 運算子下方之 Stream Aggregate 運算子所執行的部份彙總,會累積為 Parallelism 運算子上方之 Stream Aggregate 運算子中,各個不同 O_ORDERPRIORITY 值的單一 SUM 值。由於此計畫具有兩個交換區段,且平行處理原則的程度為 4,因此會使用八個執行緒。