#postgresql #postgresql-9.6 #postgresql-parallel-query
#postgresql #postgresql-9.6 #postgresql-parallel-query
Вопрос:
Из примечаний к выпуску PostgreSQL 9.6:
Могут быть распараллелены только строго доступные только для чтения запросы, в которых доступ к управляющей таблице осуществляется через последовательное сканирование.
Мой вопрос: если CTE ( WITH
предложение) содержит только операции чтения, но его результаты используются для выполнения операции записи, например, вставки или обновления, запрещено ли также распараллеливать последовательные проверки?
Я имею в виду, поскольку CTE очень похожа на временную таблицу, которая существует только для текущего выполнения запроса, могу ли я предположить, что его внутренний запрос может воспользоваться преимуществами нового параллельного seq-сканирования PostgreSQL 9.6? Или, в противном случае, он рассматривается как подзапрос using и не может выполнять параллельное сканирование?
Например, рассмотрим этот запрос:
WITH foobarbaz AS (
SELECT foo FROM bar
WHERE some_expensive_function(baz)
)
DELETE FROM bar
USING foobarbaz
WHERE bar.foo = foobarbaz.foo
;
Ожидается ли, что вычисление foobarbaz может быть распараллелено или оно запрещено из-за предложения delete?
Если это не разрешено, я подумал, что можно заменить CTE на оператор CREATE TEMPORARY TABLE . Но я думаю, что столкнусь с той же проблемой, что и CREATE TABLE — это операция записи. Я ошибаюсь?
Наконец, последний шанс, который я мог бы попробовать, — это выполнить его как операцию чистого чтения и использовать его результат в качестве входных данных для операций вставки и / или обновления. Вне транзакции это должно работать. Но вопрос в том, что если операция чтения и вставка / обновление находятся между begin
commit
предложениями и, это все равно не будет разрешено? Я понимаю, что это две совершенно разные операции, но в одной и той же транзакции и Postgres.
Чтобы быть ясным, меня беспокоит то, что у меня есть ужасная масса трудночитаемых и трудноизменяемых SQL-запросов, которые включают в себя несколько последовательных сканирований с вызовами низкоэффективных функций и которые выполняют сложные изменения над двумя таблицами. Весь процесс выполняется за одну транзакцию, потому что, если нет, беспорядок в случае сбоя будет полностью неустраним.
Я надеюсь, что смогу распараллелить некоторые последовательные проверки, чтобы использовать преимущества 8 ядер процессора компьютера, чтобы быстрее завершить процесс.
Пожалуйста, не отвечайте, что мне нужно полностью переделать этот беспорядок: Я знаю, и я работаю над этим. Но это отличный проект, и нам нужно продолжать работать.
В любом случае, любое предложение будет благодарно.
Редактировать:
Я добавляю краткий отчет о том, что я смог обнаружить до сих пор:
-
Как говорит @a_horse_with_no_name в своем комментарии (спасибо), CTE и остальная часть запроса представляют собой один оператор DML, и, если у него есть операция записи, даже за пределами CTE, то CTE не может быть распараллелен (я также тестировал его).).
-
Также я нашел эту вики-страницу с более краткой информацией о параллельных проверках, чем то, что я нашел в ссылке примечания к выпуску.
-
Интересный момент, который я мог бы проверить благодаря этой вики-странице, заключается в том, что мне нужно объявить задействованные функции как параллельные безопасные. Я сделал это и работал (в тесте без записей).
-
Еще один интересный момент — это то, что @a_horse_with_no_name говорит в своем втором комментарии: использование DbLink для выполнения чистого запроса только для чтения. Но, немного изучив это, я увидел, что postgres_fdw, который явно упоминается в wiki как не поддерживающий параллельное сканирование, обеспечивает примерно ту же функциональность с использованием более современной и соответствующей стандартам инфраструктуры.
- И, с другой стороны, даже если бы это сработало, я в конечном итоге получал данные извне транзакции, что в некоторых случаях было бы приемлемо для меня, но, я думаю, не так хорошо, как общее решение.
-
Наконец, я проверил, что возможно выполнить параллельное сканирование в запросе только для чтения внутри транзакции, даже если позже она выполняет операции записи (исключение не срабатывает, и я мог бы зафиксировать).
…таким образом, я думаю, что моим лучшим выбором (если не единственным) было бы реорганизовать скрипт таким образом, чтобы он считывал данные в память до последующего выполнения операций записи в той же транзакции.
Это увеличит накладные расходы на ввод-вывод, но с учетом задержек, которыми я управляю, это будет еще лучше.
Комментарии:
1. » могу ли я предположить, что его внутренний запрос может воспользоваться преимуществами нового параллельного seq-сканирования » нет, вы не можете. Оператор считается DML и не является кандидатом на параллельное выполнение. Не забывайте, что поддержка параллельных запросов в 9.6 является первой реализацией и все еще имеет много ограничений
2. Одним из способов обойти это может быть запуск
select
через DbLink (на тот же сервер), который затем будет рассматриваться как чистый запрос только для чтения.