PostgreSQL 11 beta: тестируем декларативное партиционирование и JIT на клиентских нагрузках
Подняли PostgreSQL 11 beta 1 рядом с продакшн DWH и прогнали реальные аналитические запросы. Partition pruning по дате ускорил выборки вдвое - готовимся к миграции.
PostgreSQL 11 Beta 1 - декларативное партиционирование с partition pruning и JIT-компиляция запросов через LLVM
PostgreSQL 11 beta 1 вышел в начале июня, и мы взяли паузу до июля - подождали пока отшумят первые баг-репорты. Потом подняли тестовый стенд рядом с одним из клиентских DWH: залили туда копию схемы и данных и прогнали реальные аналитические запросы. Рассказываем что получилось и зачем нам вообще это нужно.
Зачем тестировать бету
На сопровождаемых DWH-проектах у нас несколько хранилищ где таблицы фактов партиционированы по дате. Партиционирование в PostgreSQL 10 тоже есть - декларативное, появилось в 10.0. Но там partition pruning работал только на время планирования: если секция попадала в результат по условию на дату, планировщик её исключал. В PostgreSQL 11 добавили partition pruning при выполнении - когда условие на дату вычисляется не константой, а параметром или подзапросом. Для нас это конкретный кейс: большинство BI-инструментов передают даты через параметры, а не константы.
Плюс JIT-компиляция через LLVM - отдельная интересная история для тяжёлых аналитических запросов. Посмотреть хотелось на обе вещи.
Стенд и нагрузка
Стенд: три сервера с теми же характеристиками что и продакшн-машина клиента. PostgreSQL 11 beta 1 поставили через официальный PGDG-репозиторий для Debian, рядом с PostgreSQL 10.4 на продакшне. Схему и данные скопировали через pg_dump / pg_restore с маскировкой - клиентских данных в открытом виде на стенде нет.
Таблица фактов: несколько десятков миллионов строк, партиционирована по месяцам за три года. Типовые аналитические запросы - выборка за квартал с GROUP BY по нескольким измерениям. Именно те запросы, которые в BI идут с параметром даты, а не константой.
Partition pruning: что изменилось
В PostgreSQL 10 при параметрическом условии на дату планировщик видел $1 >= '2018-01-01' и не мог заранее исключить ненужные секции - он не знал значение параметра на этапе планирования. Результат: план включал все партиции, сканировались все, даже если по факту условие попадало в три месяца из 36.
В PostgreSQL 11 partition pruning перенесли на этап выполнения. Планировщик ставит специальный узел, который получает параметр уже в runtime и отсекает ненужные партиции до начала их чтения. EXPLAIN ANALYZE показывает это явно: у ненужных партиций в плане появляется never executed.
На нашем типовом запросе за квартал - разница в реальном времени выполнения примерно вдвое. Не на всех запросах: там где в 10-й версии оптимизатор справлялся сам (константа в условии), разницы нет. Но параметрический кейс - именно тот где нас жало.
Отдельно стоит отметить: в 11-й версии добавили поддержку DEFAULT-партиции. Раньше строки, не попавшие ни в одну секцию, вызывали ошибку при вставке - нужно было следить за тем чтобы все диапазоны были покрыты. Теперь можно объявить DEFAULT PARTITION и туда уходят остатки. Для ETL-загрузки, где иногда прилетают данные за периоды вне текущей схемы партиционирования, это полезная страховка.
JIT: включили, посмотрели
JIT в PostgreSQL 11 включается параметром jit = on (по умолчанию - on в beta, на GA наверное поменяют дефолт). Идея простая: LLVM-компилятор генерирует нативный код для выражений в запросе - вместо интерпретации в рантайме.
Нагрузка, на которой JIT что-то даёт, конкретная: тяжёлые выражения в WHERE, сложные CASE WHEN, функции над большим числом строк. На наших аналитических запросах с простыми фильтрами по дате и агрегатами SUM/COUNT - прирост от JIT минимальный, в пределах погрешности измерений. Основной выигрыш дал partition pruning, а не JIT.
На синтетическом запросе с тяжёлыми математическими выражениями по всем строкам - JIT показал заметный прирост. Но это не наш типовой профиль.
Важный момент: JIT добавляет время на компиляцию при первом выполнении плана. На коротких запросах это overhead, который съедает любой выигрыш от JIT. Порог управляется параметром jit_above_cost - по умолчанию 100000. Для OLTP-нагрузки с короткими запросами JIT лучше держать выключенным или поднять порог.
Что с совместимостью
Несколько вещей, на которые наткнулись при переносе схемы:
Хранимые процедуры - CREATE PROCEDURE. В PostgreSQL 10 есть только функции. PostgreSQL 11 добавил процедуры с CALL и поддержкой транзакций внутри. У нас их нет, но если в схеме есть функции, которые выполняют COMMIT через хитрые трюки - стоит проверить.
ALTER TABLE ... ATTACH PARTITION стал быстрее. В 10-й версии при attach крупной партиции PostgreSQL брал ACCESS EXCLUSIVE lock и проверял ограничения - на большой таблице это минуты. В 11-й можно использовать NOT VALID + VALIDATE CONSTRAINT отдельно, что снижает время удержания блокировки. Для нас актуально при ежемесячном добавлении новых партиций на продакшне.
pg_partitioned_table в pg_catalog. Появился системный каталог для партиционированных таблиц - полезно для мониторинга и утилит обслуживания.
Что с бетой не делать
Стенд - это стенд. В продакшн 11 beta 1 мы не ставим. Это первая публичная бета, и характер бета-версии PostgreSQL означает что основные функции уже зафиксированы, но баги в крайних случаях ещё будут.
Нашли один неприятный момент на стенде: при определённом сочетании partition pruning и параллельного выполнения EXPLAIN ANALYZE зависал на несколько секунд. Воспроизводится не всегда. Похоже на известный баг, который уже репортили на pgsql-hackers - будем следить.
Что дальше
PostgreSQL 11 GA ожидается осенью. До этого планируем:
- Обновить схему под 11-е API партиционирования. В нашем случае изменений минимум, но надо пройтись по скриптам управления партициями и проверить.
- Протестировать ETL-загрузку на стенде. Partition pruning при записи в PostgreSQL 11 тоже улучшили - вставка в партиционированную таблицу без указания конкретной партиции стала быстрее.
- Сделать plan по миграции - у одного из клиентов это сервис без окна на даунтайм, значит
pg_upgradeили логическая репликация.
По итогам бета-тестирования - картина достаточно чёткая, чтобы планировать миграцию после выхода GA. Partition pruning при выполнении - это не синтетика, это конкретный прирост на реальных запросах.