Планировщик классифицирует используемые в запросе операции как
parallel safe, parallel restricted,
или небезопасный для параллельного выполнения. Операция, безопасная для параллельного выполнения (parallel safe), — это операция, которая не конфликтует с использованием параллельных запросов. Операция с ограниченным параллелизмом (parallel restricted) — это операция, которая не может быть выполнена в параллельном рабочем процессе, но может быть выполнена в ведущем процессе во время выполнения параллельного запроса. Таким образом, операции с ограниченным параллелизмом не могут располагаться в плане ниже узла Gather
или Gather Merge узла, но могут встречаться в других частях плана, содержащего такой узел. Небезопасная для параллельного выполнения операция (parallel unsafe) — это операция, которая не может быть выполнена при использовании параллельного запроса даже в ведущем процессе. Если запрос содержит элементы, небезопасные для параллельного выполнения, использование параллельного запроса для него полностью отключается.
Следующие операции всегда имеют ограниченный параллелизм:
Сканирование обобщённых табличных выражений (CTE).
Сканирование временных таблиц.
Сканирование сторонних таблиц, за исключением случаев, когда обёртка сторонних данных имеет
соответствующий IsForeignScanParallelSafe API, указывающий на обратное.
Узлы плана, ссылающиеся на коррелированное SubPlan.
Планировщик не может автоматически определить, является ли пользовательская функция или агрегат безопасными для параллельного режима (parallel safe), ограниченными (parallel restricted) или небезопасными (parallel unsafe), так как для этого потребовалось бы предсказать каждую операцию, которую может выполнить функция. В общем случае это эквивалентно задаче остановки и, следовательно, невозможно. Даже для простых функций, где это теоретически возможно, такие попытки не предпринимаются, так как это было бы слишком ресурсозатратно и привело бы к ошибкам. Вместо этого все пользовательские функции по умолчанию считаются небезопасными для параллельного выполнения (parallel unsafe), если не указано иное. При использовании
CREATE FUNCTION или
ALTER FUNCTION, маркировки устанавливаются путем указания
PARALLEL SAFE, PARALLEL RESTRICTEDили
PARALLEL UNSAFE соответствующим образом. При использовании
CREATE AGGREGATE, параметр
PARALLEL может быть указан с SAFE,
RESTRICTEDили UNSAFE в качестве соответствующего значения.
Функции и агрегаты должны быть помечены PARALLEL UNSAFE
если они выполняют запись в базу данных, изменяют состояние транзакции (за исключением использования подтранзакций для восстановления после ошибок), обращаются к последовательностям или вносят постоянные изменения в параметры. Аналогичным образом, функции должны быть помечены как PARALLEL
RESTRICTED если они обращаются к временным таблицам, состоянию клиентского соединения, курсорам, подготовленным операторам или различному локальному состоянию серверного процесса, которое система не может синхронизировать между рабочими процессами. Например,
setseed и random имеют категорию parallel restricted по этой последней причине.
В общем случае, если функция помечена как безопасная (safe), когда она является ограниченной (restricted) или небезопасной (unsafe), либо если она помечена как ограниченная, когда на самом деле она небезопасна, это может привести к возникновению ошибок или выдаче неверных ответов при использовании в параллельном запросе. Функции на языке C теоретически могут демонстрировать неопределенное поведение в случае неправильной маркировки, так как у системы нет возможности защитить себя от произвольного C-кода, но в большинстве вероятных случаев результат будет не хуже, чем для любой другой функции. При наличии сомнений наиболее целесообразно помечать функции как UNSAFE.
Если функция, выполняемая в параллельном рабочем процессе, устанавливает блокировки, которые не удерживаются ведущим процессом (например, при выполнении запроса к таблице, не указанной в основном запросе), такие блокировки будут сняты при завершении рабочего процесса, а не в конце транзакции. Если вы создаете функцию с таким поведением и данное различие является критичным, следует пометить такие функции как
PARALLEL RESTRICTED
чтобы гарантировать их выполнение только в ведущем процессе.
Обратите внимание, что планировщик запросов не рассматривает возможность отложенного вычисления функций или агрегатов с ограничением параллелизма (parallel-restricted), задействованных в запросе, ради получения более оптимального плана. Так, например, если WHERE
предложение, применяемое к определенной таблице, имеет ограничение параллелизма, планировщик запросов не будет рассматривать возможность сканирования этой таблицы в параллельной части плана. В некоторых случаях было бы возможно (и, вероятно, даже эффективно) включить сканирование этой таблицы в параллельную часть запроса и отложить вычисление
WHERE предложение таким образом, чтобы это действие выполнялось выше Gather
node. Однако планировщик этого не делает.