Skip to content

Всё о GUC по порядку: enable_async_append

Автор: Christophe Pettus, All Your GUCs in a Row: enable_async_append


Мы подошли к семейству параметров enable_* — более чем двум десяткам переключателей планировщика, которые по умолчанию включены и объединены одним важнейшим свойством: они не являются регулировочными ручками. Это диагностические инструменты. Каждый из них отключает способность планировщика рассматривать определённый тип плана, и причина, по которой такая возможность существует, заключается в том, чтобы инженер, преследующий «плохой» план, мог заставить планировщик показать свою вторую альтернативу, — спросить: «Что бы ты сделал, если бы этот тип узла был недоступен?» Отключение одного из них в рабочей среде для ускорения запроса почти всегда является ошибкой; на самом деле вы хотите понять, почему планировщик предпочёл план, который вам не понравился, и эти переключатели — способ его «допроса». Каждая статья в этом семействе будет повторять некоторую версию этого предупреждения, потому что каждый из этих параметров используется неправильно одинаковым образом.

С этим установленным, enable_async_append — хорошее начало, поскольку он управляет действительно современной функцией, а не узлом плана десятилетней давности. По умолчанию включён, контекст — user.



Что такое асинхронное добавление (async append)



Узел Append — это то, что планировщик строит, когда запрос получает строки из нескольких источников, которые конкатенируются, — секции секционированной таблицы, ветви UNION ALL. Обычно Append обрабатывает свои дочерние элементы последовательно: сканирует первый до завершения, затем второй и так далее. Это последовательное выполнение хорошо, когда дочерние элементы являются локальными кучами, которые ЦП «проглатывает», и оно категорически не подходит, когда дочерние элементы являются внешними таблицами на удалённых серверах, потому что тогда каждое сканирование дочернего элемента большую часть своего времени ожидает сетевого ответа, и выполнение их одно за другим означает, что общее время вашего запроса равно сумме задержек каждого удалённого сервера, уплаченной последовательно.



Асинхронное добавление, добавленное в PostgreSQL 14, исправляет именно это. Когда дочерние элементы Append являются внешними сканированиями против разных серверов, Append, поддерживающий асинхронность, запускает удалённые запросы параллельно и собирает результаты по мере их поступления, поэтому запрос ожидает примерно столько же, сколько самый медленный шард, а не сумму всех их. В EXPLAIN узел отображается как Async Foreign Scan, и разница между суммированием задержек десяти шардов и ожиданием одного из них — это разница между тем, будет ли аналитический запрос, использующий шардирование через FDW, пригодным к использованию или предметом для насмешек. Это был настоящий рубеж для истории шардирования PostgreSQL через обёртки внешних данных — впервые запрос, охватывающий шарды, мог выполняться параллельно, а не «тащиться» от сервера к серверу.



Существует требование, которое сбивает людей с толку: функция включается только тогда, когда внешние таблицы помечены как async_capable — опция, которую вы устанавливаете на внешнем сервере (или для каждой внешней таблицы), и которая по умолчанию имеет значение false. Таким образом, асинхронное добавление имеет два переключателя — этот GUC, включённый по умолчанию, и опцию сервера async_capable, выключенную по умолчанию, — и тот, который вам, скорее всего, нужно переключить, — это второй. GUC определяет, будет ли планировщик вообще рассматривать асинхронное добавление; опция сервера определяет, соглашаются ли ваши конкретные внешние таблицы на это. Внешний сервер, оставленный с async_capable = false по умолчанию, получает последовательные внешние сканирования независимо от того, как установлен enable_async_append.



Когда вам стоит трогать этот GUC



Он почти исключительно для диагностики. Симптом, который должен заставить вас к нему обратиться, — конкретный: запрос к секционированной таблице, секции которой являются внешними таблицами, или любой UNION ALL по внешним серверам, выполняющийся заметно медленнее, чем самый медленный отдельный шард, и EXPLAIN ANALYZE, чьё общее время подозрительно похоже на сумму времён отдельных сканирований Foreign Scan, а не на их максимум. Если вы видите обычные узлы Foreign Scan под Append там, где ожидали Async Foreign Scan, планировщик либо не выбрал асинхронное добавление, либо ему не было позволено, и вопрос заключается в том, что именно. Переключение этого GUC — это способ ответить на половину этого вопроса: если SET enable_async_append = off ничего не меняет в плане, который уже был последовательным, планировщик изначально не использовал асинхронное добавление, и ваша проблема находится выше по течению, — скорее всего, в опции сервера async_capable, как указано ниже. Если в плане действительно были узлы Async Foreign Scan и вы хотите измерить, чего они стоят, отключение GUC и повторный запуск EXPLAIN (ANALYZE) даёт вам последовательную базовую линию для сравнения. Это законное использование: контролируемый эксперимент в сеансе, который вы закроете.



В документации отмечен один реальный производственный случай для отключения асинхронного выполнения, но он относится к опции async_capable, а не к этому GUC: поскольку postgres_fdw использует одно подключение на внешний сервер и выполняет запросы этого сервера последовательно через него, план, который ссылается на один и тот же внешний сервер в нескольких местах, может видеть, что асинхронное выполнение добавляет накладные расходы на координацию без реального прироста параллелизма, и в этом случае отключение async_capable может быть быстрее. Это решение о настройке для конкретного сервера, касающееся FDW, а не причина отключать возможность асинхронного добавления планировщика для всего кластера.



Поэтому оставьте enable_async_append включённым, чтобы планировщик мог использовать параллелизм, когда шардированный запрос может его применить. Если ваши запросы между шардами выполняют внешние сканирования последовательно, когда вы ожидали параллелизма, рычаг управления почти наверняка находится в опции async_capable на внешнем сервере, а не в этом параметре, — и если вы вообще тянетесь к этому параметру, вы должны делать это в диагностическом сеансе с EXPLAIN, что является правильной и единственной хорошей причиной для трогания любого члена семейства, которое мы только что открыли.

Trackbacks

No Trackbacks

Comments

Display comments as Linear | Threaded

No comments

The author does not allow comments to this entry

Add Comment

Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
Standard emoticons like :-) and ;-) are converted to images.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

Form options

Submitted comments will be subject to moderation before being displayed.