PostgreSQL 17 Beta 1: переработанный VACUUM - гоняем на тестовом стенде рядом с PG 16
PostgreSQL 17 Beta 1 вышел с переработанным VACUUM, улучшенным планировщиком и JSON SQL/2023. Разворачиваем тестовую среду и сравниваем поведение на OLTP-нагрузке.
PostgreSQL 17 Beta 1 вышел с переработанным VACUUM, улучшенным query planner и новыми функциями JSON SQL/2023
PostgreSQL выпустил Beta 1 семнадцатой версии - и в этот раз анонс зацепил нас сильнее, чем обычно. Не потому что JSON SQL/2023 или query planner (хотя и это интересно), а потому что в changelog первым пунктом идёт переработанный VACUUM. Для DWH и высоконагруженных OLTP-баз, где vacuum - это не фоновый шум, а полноценный участник производительности, это прямо по адресу.
Бета - не продакшн, но разворачивать стенд и смотреть поведение лучше сейчас, чем за неделю до GA.
Что изменили в VACUUM
Основное изменение в PG 17 - переработка внутреннего цикла autovacuum и алгоритма обработки мёртвых строк. Если коротко: в старом поведении VACUUM при обходе таблицы накапливал список мёртвых tuple-идентификаторов (TID) в памяти, и когда буфер заканчивался (maintenance_work_mem или лимит autovacuum_work_mem), приходилось прерываться, лезть в индексы, чистить их, и начинать заново. На больших таблицах это могло выродиться в несколько проходов по индексам.
В PG 17 алгоритм переработан: VACUUM теперь делает за один проход по таблице полную разметку того, что нужно убрать, и число проходов по индексам сокращается. На таблицах с агрессивной update-нагрузкой - а это типичный OLTP с частыми изменениями строк - разница в объёме I/O при вакуумировании должна быть заметной.
Второй момент - изменения в vacuumlo. Утилита для очистки осиротевших large objects стала менее навязчивой при работе в транзакции. Это нишевый кейс, но у одного из наших клиентов есть устаревший пайплайн, который активно использует lo - там посмотрим отдельно.
Стенд: PG 16 vs PG 17 Beta 1 рядом
Развернули два инстанса на одном железе: PG 16.3 и PG 17 Beta 1. Железо - обычный тестовый сервер, не продакшн. Конфигурация намеренно одинаковая: shared_buffers, work_mem, autovacuum_vacuum_cost_delay - зеркальные значения на обоих.
Для нагрузки взяли синтетику, максимально похожую на реальный OLTP: таблица с ~50 млн строк, интенсивный поток UPDATE по случайным ID, параллельно SELECT-запросы по диапазонам. Это условия, при которых мёртвые строки накапливаются быстро и VACUUM работает непрерывно.
Что наблюдали через pg_stat_io и pg_stat_user_tables:
- Число index scan в рамках autovacuum - на PG 17 заметно меньше при той же интенсивности UPDATE. На нашем стенде примерно вдвое, но это синтетика, реальные цифры будут зависеть от соотношения
maintenance_work_memк размеру таблицы. - Время вакуумирования одного цикла - чуть короче, что важно не само по себе, а потому что vacuumed table остаётся под lock на этот период. Меньше циклов - меньше шанс словить конкуренцию с боевыми запросами.
n_dead_tupв динамике - на обоих инстансах autovacuum справляется, принципиальной разницы в steady-state нет. Но в моменты всплеска UPDATE - когда мёртвые строки накапливаются быстрее, чем autovacuum успевает - PG 17 восстанавливается чуть быстрее.
Важная оговорка: это бета, и гонять такие сравнения надо понимая, что поведение может измениться до GA.
Query planner: что интересного
В PG 17 улучшена оценка строк для некоторых паттернов с подзапросами и CTE. На нашем стенде запустили несколько тяжёлых аналитических запросов с WITH - в паре случаев планировщик выбрал более удачный join-порядок без дополнительных хинтов. Проверяли через EXPLAIN ANALYZE, разница видна в estimated vs actual rows.
Это не революция, но планировщик PG - это система, которую улучшают итерационно, и каждое улучшение оценки рядов сокращает количество случаев, когда нужно вручную помогать через enable_* параметры или материализацию CTE.
JSON SQL/2023: смотрим, но не торопимся
PG 17 дополняет поддержку стандарта JSON SQL/2023 - в частности, функции JSON_TABLE, JSON_EXISTS, JSON_QUERY и JSON_VALUE теперь работают в рамках SQL-стандарта. Это хорошо с точки зрения переносимости - одинаковый синтаксис с другими СУБД.
На практике у большинства наших клиентов JSON в PostgreSQL хранится или в jsonb с операторами ->>, @>, или через специализированные колонки. Переход на ISO-функции - скорее вопрос новых проектов, чем миграции существующего кода. Пощупали на стенде - работает, синтаксис непривычный после операторного подхода, но для кросс-СУБД совместимости аргумент есть.
Что дальше
Beta 1 - это начало цикла. До GA обычно несколько бета-итераций и RC, исторически это занимает несколько месяцев. В продакшн PG 17 раньше конца года не пойдёт - и не должен.
Наш план: держать тестовый стенд актуальным по мере выхода следующих бет, особенно в части VACUUM - это то, что реально влияет на поведение под нагрузкой. Если поведение с maint_work_mem и агрессивным UPDATE подтвердится на Beta 2-3, к моменту GA у нас будет чёткое понимание, что изменить в autovacuum-конфигурации при миграции.
Пока - PG 16 в продакшне, PG 17 на стенде. Так и должно быть с бетой.