Пример параллельного запроса

В нижеследующем запросе подсчитывается количество заказов, размещенных в течение указанного квартала, начиная с 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, использует соединение двух таблиц

Иллюстрация демонстрирует план оптимизатора запросов, выполняемый со степенью параллелизма, равной 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, он использует восемь потоков.

См. также

Основные понятия