Пример параллельного запроса
В нижеследующем запросе подсчитывается количество заказов, размещенных в течение указанного квартала, начиная с 1 апреля 2000, в которых хотя бы один элемент из списка заказанных товаров был получен заказчиком позже фиксированной даты. В этом запросе представлен подсчет таких заказов, сгруппированных в соответствии со срочностью каждого заказа и отсортированных в возрастающем порядке.
В этом примере используются теоретические имена таблицы и столбцов.
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. Оба оператора, Index Seek индекса o_datkey_ptr и Index Scan индекса l_order_dates_idx, выполняются параллельно. В результате образуется несколько исключающих потоков. Это может быть определено из ближайших операторов Parallelism над операторами Index Scan и Index Seek, соответственно. Оба перераспределяют тип обмена. То есть они всего лишь перегруппируют данные между потоками и выдают в результате столько же потоков на выходе, сколько их было на входе. Количество потоков равно степени параллелизма.
Оператор Parallelism над оператором Index Scanl_order_dates_idx перераспределяет свои входные потоки с использованием значения L_ORDERKEY в качестве ключа. В этом случае те же значения L_ORDERKEY выдаются в том же выходном потоке. Одновременно в потоках выхода поддерживается порядок в столбце L_ORDERKEY для соответствия входному требованию оператора Merge Join.
Оператор Parallelism над оператором Index Seek перераспределяет свои входные потоки с использованием значения O_ORDERKEY. Поскольку его входные данные не сортируются по значениям столбца O_ORDERKEY, а он является столбцом соединения в операторе Merge Join, оператор Sort между операторами Parallelism и Merge Join обеспечивает сортировку входных данных для оператора Merge Join по столбцам соединения. Оператор Sort, как и оператор Merge Join, выполняется параллельно.
Первый оператор Parallelism соединяет результаты из нескольких потоков в один. Результаты частичной статистической обработки, выполняемой оператором Stream Aggregate под оператором Parallelism, затем собираются в единое значение SUM для каждого отдельного значения O_ORDERPRIORITY в операторе Stream Aggregate над оператором Parallelism. Поскольку этот план состоит из двух сегментов обмена со степенью параллелизма, равной 4, он использует восемь потоков.