ADG Оставить заявку
Блог Данные и аналитика 4 мин чтения

PostgreSQL 13 Beta 2: тестируем дедупликацию B-tree индексов на копии production БД

Гоняем PostgreSQL 13 Beta 2 на production-слепке DWH: дедупликация B-tree сократила объём индексов, параллельный VACUUM снизил bloat в OLTP-таблицах.

Контекст момента

PostgreSQL 13 Beta 2: дедупликация B-tree индексов и улучшенный параллелизм VACUUM

PostgreSQL 13 вышел во второй бете на прошлой неделе, и мы решили не ждать GA, а сразу поднять копию production-базы и посмотреть, что реально меняется. Основные два гвоздя релиза, которые нас интересуют применительно к DWH-задачам: дедупликация B-tree индексов и параллельный VACUUM. Рассказываем что увидели.

Стенд

Слепок production PostgreSQL 12.3 - один из наших DWH-серверов, данные реальные, нагрузка воспроизводилась через pg_replay с записанным трафиком. Версия для теста: PostgreSQL 13 Beta 2, собранная из исходников на том же железе. Объём базы - порядка 400 GB, смесь аналитических таблиц с историческими данными и OLTP-таблиц с высокой частотой INSERT/UPDATE.

pg_upgrade --check прошёл чисто, фактический upgrade не делали - цель была посмотреть на новые механики, а не катить бету в production.

Дедупликация B-tree: где она работает и где нет

Главная фича 13-й версии для нас - deduplication в B-tree индексах. Суть: если в индексируемом столбце много повторяющихся значений, PostgreSQL 13 хранит (value, [tid1, tid2, tid3...]) вместо отдельной записи на каждый tid. Это называется deduplicated posting list.

По умолчанию дедупликация включена для всех новых индексов. На существующих надо пересобрать через REINDEX.

Мы прогнали REINDEX DATABASE на копии и сравнили pg_relation_size до и после для каждого индекса. Несколько наблюдений:

  • Таблицы статусов и справочников - там где status_id, region_id, type_code с небольшим количеством уникальных значений - дали наиболее заметный эффект. По ряду индексов размер упал примерно на 18% относительно 12-й версии на тех же данных. Не на всех - только там где cardinality низкая.
  • Уникальные индексы дедупликация не трогает - там по определению нет дублей. Это логично, но стоит держать в голове: если большая часть ваших индексов уникальные, выигрыш будет скромным.
  • Частичные индексы работают с дедупликацией нормально, проблем не заметили.
  • Индексы по expression - здесь ситуация зависит от типа выражения. У нас несколько индексов по lower(email) и date_trunc('day', created_at) - там cardinality высокая, и выигрыша почти нет.

В целом: дедупликация B-tree - это не серебряная пуля, а прицельная оптимизация для конкретного паттерна. Если у вас много индексов по столбцам с низкой уникальностью (enum-поля, FK на небольшие справочники, булевы флаги) - эффект будет ощутимый. Если в основном уникальные индексы по суррогатным ключам - разочарования не избежать.

Параллельный VACUUM

В PostgreSQL 13 VACUUM умеет работать с несколькими worker-процессами для одной таблицы - через параметр parallel_workers или опцию VACUUM (PARALLEL n). До этого параллелизм у VACUUM был только в autovacuum на уровне разных таблиц.

На OLTP-таблицах с активным bloat картина была интересная. Взяли самые проблемные таблицы по pg_stat_user_tables.n_dead_tup - там где bloat накапливается быстро из-за частых UPDATE. Запустили обычный VACUUM (12-й версии эквивалент) и параллельный VACUUM (PARALLEL 4) на копии.

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

Оговорка: параллелизм VACUUM нагружает I/O. На стенде у нас изолированное железо, в production с общим дисковым стеком результат может быть другим. Надо смотреть на pg_stat_bgwriter и I/O pressure в реальных условиях, прежде чем агрессивно поднимать max_parallel_maintenance_workers.

Autovacuum параллелизм не использует автоматически в Beta 2 - только ручной VACUUM. Возможно это изменится до GA, но пока так.

Что ещё заметили по ходу

Мимоходом натолкнулись на улучшенную статистику по расширенным типам данных - pg_stats_ext в 13-й версии получил дополнительные поля. Для наших аналитических запросов с GROUP BY по нескольким столбцам планировщик в паре мест выбрал более адекватный план, чем 12-я версия на тех же данных. Воспроизводимо ли это систематически - не ясно, нужно больше наблюдений.

Ещё: EXPLAIN (ANALYZE, BUFFERS) теперь показывает WAL-статистику - сколько записей и байт сгенерировано запросом. Мелочь, но приятно: раньше приходилось считать через pg_waldump или снимать pg_current_wal_lsn() до и после.

Итог на сейчас

Бета есть бета - в production мы её не катим и не планируем. Но тест на реальных данных показал, что дедупликация B-tree работает именно так как описано в документации, без сюрпризов. Экономия индексного пространства на наших данных реальная - для таблиц с FK и enum-полями цифра около 18% выглядит воспроизводимо. Параллельный VACUUM интересен, но требует аккуратной настройки под конкретный I/O-профиль.

GA ожидается осенью, к тому моменту посмотрим как сообщество обкатает бету и какие проблемы всплывут. Пока наблюдаем.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.