15.3. Параллельные планы

Because each worker executes the parallel portion of the plan to completion, it is not possible to simply take an ordinary query plan and run it using multiple workers. Each worker would produce a full copy of the output result set, so the query would not run any faster than normal but would produce incorrect results. Instead, the parallel portion of the plan must be what is known internally to the query optimizer as a partial plan; that is, it must constructed so that each process which executes the plan will generate only a subset of the output rows in such a way that each required output row is guaranteed to be generated by exactly one of the cooperating processes.

15.3.1. Параллельные сканирования

В настоящее время единственным вариантом сканирования, адаптированным для работы в параллельном режиме, является последовательное сканирование. Таким образом, целевая таблица в параллельном плане всегда будет сканироваться узлом Parallel Seq Scan. Блоки отношения разделяются между сотрудничающими процессами и выдаются им по одному, так что доступ к отношению остаётся последовательным. Каждый отдельный процесс сначала посещает все кортежи на назначенной ему странице, и только затем переходит к новой.

15.3.2. Параллельные соединения

Целевая таблица может соединяться с одной или несколькими другими таблицами, используя вложенные циклы или соединения по хешу. Внешней стороной соединения может быть любой вид не параллельного плана, который в остальном поддерживается планировщиком, с условием того, что он безопасен для выполнения в параллельном исполнителе. Например, это может быть сканирование индекса, при котором находится значение по колонке, взятой из внутренней таблицы. Каждый рабочий процесс будет выполнять внешнюю сторону плана в полном объёме, поэтому соединения слияниям в таком режиме не поддерживаются. Внешняя сторона соединения слиянием часто включает сортировку всей внутренней таблицы; даже если при этом задействуется индекс, вряд ли будет продуктивным действие несколько процессов, производящих полное сканирование по индексу этой внутренней таблицы.

15.3.3. Параллельное агрегирование

Часть запроса, собственно производящую агрегирование, невозможно выполнять полностью в параллельном режиме. Например, если запрос включает выборку COUNT(*), каждый рабочий процесс сможет подсчитать своё количество строк, но эти количества нужно будет сложить, чтобы получить окончательный ответ. Если запрос включает предложение GROUP BY, отдельное общее количество надо будет вычислять для каждой группы. И даже несмотря на то, что агрегирование нельзя осуществлять полностью параллельно, запросы с агрегированием часто становятся отличными кандидатами на распараллеливание, так как они обычно читают множество строк, но возвращают клиенту только небольшое их число. Запросы, возвращающие клиенту множество строк, часто ограничены скоростью, с которой клиент может принимать данные, так что в таких случаях параллельное выполнение запроса может быть не очень полезным.

Postgres Pro поддерживает параллельное агрегирование, выполняя агрегирование дважды. Сначала каждый процесс, задействованный в параллельной части запроса, выполняет шаг агрегирования, выдавая частичный результат для каждой известной ему группы. В плане это отражает узел PartialAggregate. Затем эти промежуточные результаты передаются ведущему через узел Gather. И наконец, ведущий заново агрегирует результаты всех рабочих процессов, чтобы получить окончательный результат. Это отражает в плане узел FinalizeAggregate.

Параллельное агрегирование поддерживается не во всех случаях. Чтобы оно поддерживалось, агрегатная функция должна быть безопасной для распараллеливания и должна иметь комбинирующую функцию. Если переходное состояние агрегатной функции имеет тип internal, она должна также иметь функции сериализации и десериализации. За подробностями обратитесь к CREATE AGGREGATE. Параллельное агрегирование не поддерживается для сортирующих агрегатов или когда запрос включает предложение GROUPING SETS. Оно может использоваться только когда все соединения, задействованные в запросе, также входят в параллельную часть плана.

15.3.4. Советы по параллельным планам

Если для запроса ожидается параллельный план, но такой план не строится, можно попытаться уменьшить parallel_setup_cost или parallel_tuple_cost. Разумеется, этот план может оказаться медленнее последовательного плана, предпочитаемого планировщиком, но не всегда. Если вы не получаете параллельный план даже с очень маленькими значениями этих параметров (например, сбросив оба их в ноль), может быть какая-то веская причина тому, что планировщик запросов не может построить параллельный план для вашего запроса. За информацией о возможных причинах обратитесь к Разделу 15.2 и Разделу 15.4.

When executing a parallel plan, you can use EXPLAIN (ANALYZE, VERBOSE) to display per-worker statistics for each plan node. This may be useful in determining whether the work is being evenly distributed between all plan nodes and more generally in understanding the performance characteristics of the plan.