병렬 쿼리 예제
다음 쿼리에서는 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로 실행되고 두 개의 테이블 조인을 포함하는 쿼리 최적화 프로그램 계획을 보여 줍니다.
이 병렬 계획에는 세 개의 Parallelism 연산자가 포함됩니다. 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인 두 개의 교환 세그먼트가 있으므로 8개의 스레드가 사용됩니다.