Всё о 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
The author does not allow comments to this entry
Comments
Display comments as Linear | Threaded