ZIM-НИЙ SAAALEЗимние скидки: до −50% на старт и −20% на продление
до 31.01.2026 Подробнее
Выберите продукт

PostgreSQL: pg_repack vs VACUUM FULL — как лечить bloat без простоев

Откуда берётся bloat в PostgreSQL и почему обычный VACUUM не отдаёт место ОС. Сравниваем VACUUM FULL и pg_repack по блокировкам, диску, WAL и рискам, разбираем роль REINDEX и даём чек-лист безопасного запуска в продакшене.
PostgreSQL: pg_repack vs VACUUM FULL — как лечить bloat без простоев

Почему в PostgreSQL вообще появляется bloat

Под postgres bloat обычно понимают «раздувание» таблиц и индексов: физический размер на диске растёт, а полезных данных (с точки зрения пользователя) не прибавляется. В продакшене это проявляется так:

  • растёт расход диска и упираетесь в лимиты/квоты;
  • хуже производительность из-за лишних страниц: больше чтения и из диска, и из кеша;
  • дольше идут backup/restore и репликация из-за выросшего объёма;
  • индексы «рыхлеют», растёт число блоков, которые нужно читать.

Корень проблемы в MVCC: при UPDATE/DELETE PostgreSQL не переписывает строку «на месте», а создаёт новую версию, а старую помечает как невидимую. Эти «мертвые» версии (dead tuples) со временем должны быть вычищены VACUUM. Но обычный VACUUM в большинстве случаев не возвращает место операционной системе: он лишь делает его пригодным для повторного использования внутри того же объекта.

Табличный bloat и индексный bloat — это разные истории

У таблиц bloat появляется из-за накопления dead tuples, а также из-за неудачно выбранного fillfactor при интенсивных обновлениях. У индексов эффект похож (лишние страницы), но механизм иной: даже если dead tuples в таблице уже вычищены, индекс может оставаться большим и фрагментированным.

Поэтому в реальной эксплуатации обычно решают две задачи: уплотнить таблицу и привести в порядок индексы. Дальше начинается выбор: VACUUM FULL, pg_repack и/или отдельные операции REINDEX.

Как понять, что пора лечить bloat

Переходить к «тяжёлой артиллерии» стоит не по ощущению «что-то место жрёт», а по наблюдаемым сигналам:

  • таблица/индекс заметно выросли, а бизнес-объём данных примерно тот же;
  • после массовых удалений место на диске не возвращается;
  • время запросов выросло, а планы и профили показывают чтение большого числа блоков;
  • автовакуум не успевает, и n_dead_tup стабильно высокий.

Быстрая диагностика: где «жир»

Минимальный набор запросов, чтобы увидеть кандидатов на перепаковку и понять, что происходит с вакуумом:

-- Топ таблиц по размеру (таблица + TOAST + индексы)
SELECT
  n.nspname AS schema,
  c.relname AS table,
  pg_size_pretty(pg_total_relation_size(c.oid)) AS total_size,
  pg_size_pretty(pg_relation_size(c.oid)) AS table_size,
  pg_size_pretty(pg_total_relation_size(c.oid) - pg_relation_size(c.oid)) AS indexes_toast_size
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'r'
  AND n.nspname NOT IN ('pg_catalog','information_schema')
ORDER BY pg_total_relation_size(c.oid) DESC
LIMIT 20;
-- Мертвые строки и активность autovacuum по таблицам
SELECT
  schemaname,
  relname,
  n_live_tup,
  n_dead_tup,
  last_vacuum,
  last_autovacuum,
  last_analyze,
  last_autoanalyze
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC
LIMIT 20;

Если видите большой разрыв между размером и «ожидаемым» объёмом, а n_dead_tup либо долго не падает, либо таблица пережила массовое удаление — есть смысл планировать reclaim (возврат места).

Важно: bloat не всегда «поломка». Если таблица постоянно обновляется и место активно переиспользуется, большой физический размер может быть нормой. Лечить стоит там, где размер стабильно не используется повторно или индексы реально деградировали.

Если хотите глубже разобраться с мониторингом и лечением bloat, удобно держать под рукой отдельный разбор: практика работы с pg_repack и bloat в PostgreSQL.

Диагностика bloat в PostgreSQL: размеры таблиц и количество dead tuples

VACUUM FULL: что делает и почему его боятся

VACUUM FULL переписывает таблицу в новый физический файл, уплотняя данные. В итоге место действительно возвращается операционной системе, но цена за это — блокировки, длительность и нагрузка.

Ключевые свойства VACUUM FULL

  • Блокировки: берёт эксклюзивную блокировку на таблицу и фактически останавливает нормальный DML на время операции.
  • Возврат места ОС: да, это один из самых прямых способов уменьшить файл таблицы.
  • Индексы: индексы фактически пересоздаются на переписанной таблице, что может занять много времени.
  • WAL/репликация: генерирует много WAL; на больших таблицах это легко превращается в заметный lag реплик.
  • Требования по диску: нужен запас под переписывание. Планируйте консервативно, как под худший случай.

Когда VACUUM FULL оправдан

На практике VACUUM FULL выбирают, когда есть окно обслуживания и вы готовы к блокировке, либо когда нельзя ставить расширения/использовать внешний инструмент. Типовые кейсы:

  • небольшие таблицы, где операция займёт минуты, а не часы;
  • разовая «уборка» после массовой чистки данных;
  • жёсткие ограничения по регламентам на установку расширений.
FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

pg_repack: тот же эффект, но с минимальными блокировками

pg_repack — инструмент, который позволяет уплотнить таблицу и/или индексы с минимальным временем блокировки. По сути он делает компактную копию объекта и аккуратно переключает её вместо исходной.

Как pg_repack работает на практике

Если очень грубо, логика такая:

  • создаёт рядом новую «упакованную» таблицу;
  • отслеживает изменения исходной таблицы, чтобы догонять новую копию;
  • копирует данные и строит индексы на новой версии;
  • на короткое время берёт блокировку и выполняет атомарную подмену.

Благодаря этому сервис обычно продолжает работать, а «окно» блокировки сводится к переключению. Но на горячих таблицах и при длинных транзакциях это окно может растянуться заметно сильнее, чем ожидается.

Плюсы pg_repack

  • Минимум простоя: в большинстве случаев это «почти онлайн» операция.
  • Возврат места ОС: да, файл реально уменьшается.
  • Гибкость: можно идти точечно (таблица/индекс), не трогая весь кластер.

Минусы и риски pg_repack, о которых часто забывают

  • Запас по диску: пока создаётся новая копия, нужно место почти как под второй комплект данных плюс индексы.
  • Нагрузка: чтение таблицы, построение индексов, активная запись WAL — это I/O и CPU.
  • Долгие транзакции: могут мешать финальной подмене и удерживать блокировки дольше.
  • DDL-конкуренция: параллельные ALTER TABLE и миграции схемы — частая причина сбоев; лучше заморозить DDL на время операции.
  • Операционная дисциплина: нужен контроль репликации, WAL, свободного места и тайминга.

pg_repack vs VACUUM FULL: сравнение по критериям

Выбор лучше делать не по «красивее/страшнее», а по ограничениям продакшена:

  • Блокировки: VACUUM FULL блокирует таблицу надолго; pg_repack обычно блокирует кратко на финальном переключении.
  • Время выполнения: зависит от объёма и I/O; pg_repack может идти дольше из-за механики догонки изменений, но выигрывает отсутствием простоя.
  • Требования к диску: обоим нужен запас, но у pg_repack он почти всегда должен быть «комфортным», иначе операция просто не начнётся или сорвётся по месту.
  • Влияние на репликацию: оба генерируют WAL; на больших таблицах легко получить лаг.
  • Предсказуемость: VACUUM FULL проще по составу действий; у pg_repack больше движущихся частей, зато меньше downtime.

Где тут REINDEX и зачем он нужен

Часть «проблем производительности» — это именно индексный bloat или деградация структуры индекса. Важно держать границы инструментов:

  • REINDEX перестраивает индекс, но не уменьшает таблицу.
  • VACUUM FULL переписывает таблицу и приводит индексы в порядок в процессе.
  • pg_repack может уплотнить и таблицу, и индексы с минимальными блокировками.

Когда достаточно REINDEX

Если таблица сама по себе относительно компактная, а проблема явно в индексе (например, индекс «в разы больше нормы» или резко вырос после серии обновлений), иногда достаточно перестроить индекс. Для продакшена обычно рассматривают конкурентное перестроение там, где оно уместно, чтобы снизить влияние на запись.

Сценарий «таблицу не трогаем, индексы лечим»

Этот подход часто выручает, когда:

  • таблица активно пишется, и перепаковка слишком рискованна по времени и нагрузке;
  • мало диска, и под «вторую копию таблицы» места нет;
  • проблема локализована в одном-двух индексах (например, на колонках с интенсивными обновлениями).

Практический чек-лист: как делать перепаковку безопасно

Неважно, выбрали вы VACUUM FULL или pg_repack: подготовка обычно важнее самого инструмента.

1) Проверьте свободное место и временные файлы

Самая частая авария — закончился диск в процессе. Для больших таблиц закладывайте запас под:

  • временную копию данных;
  • построение индексов;
  • рост WAL во время операции;
  • временные файлы сортировок при создании индексов.

2) Найдите и уберите «долгоживущие» транзакции

Длинные транзакции мешают и вакууму, и repack: удерживают старые версии строк и могут растянуть блокировки в самый неподходящий момент.

-- Топ долгих транзакций
SELECT
  pid,
  usename,
  state,
  xact_start,
  now() - xact_start AS xact_age,
  wait_event_type,
  wait_event,
  left(query, 200) AS query
FROM pg_stat_activity
WHERE xact_start IS NOT NULL
ORDER BY xact_age DESC
LIMIT 20;

3) Заморозьте DDL-миграции на время операции

Любые ALTER TABLE, добавление индексов, переименование колонок во время перепаковки — это лишняя неопределённость. На практике проще ввести «freeze» на DDL на время обслуживания.

4) Контролируйте репликацию и WAL

Если есть реплики, заранее определите допустимый lag. На крупных таблицах перепаковка легко «заливает» канал WAL, а следом ухудшает RPO/RTO и задержки чтения с реплики. По теме восстановления и роли WAL полезно: как устроен PITR и восстановление PostgreSQL через WAL.

5) Планируйте окно и откат

Даже если pg_repack «почти онлайн», лучше иметь окно пониженной активности и заранее подготовить:

  • актуальный бэкап;
  • критерии остановки операции (когда вы её прерываете);
  • план возврата, если после перепаковки что-то пошло не так.
FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Типовые сценарии выбора

Сценарий A: таблица очень большая, сервис 24/7

Чаще всего выбор склоняется к pg_repack. Если bloat связан с жизненным циклом данных (например, вы постоянно удаляете «старое»), иногда правильнее лечить причину: партиционирование и дешевое «выбрасывание» старых партиций вместо массовых DELETE. В инфраструктуре это удобнее вести на предсказуемых ресурсах (например, на VDS с гарантированным диском и I/O).

Сценарий B: есть ночное окно обслуживания и умеренные объёмы

Можно рассматривать VACUUM FULL как более простой и предсказуемый вариант, особенно если таблица не огромная и вы уверены, что уложитесь по времени и по месту.

Сценарий C: место на диске заканчивается прямо сейчас

«Заканчивается диск» — плохой момент для перепаковки: и VACUUM FULL, и pg_repack требуют свободного места. Часто сначала приходится сделать одно из следующих действий:

  • убрать старые бэкапы и временные файлы;
  • расширить том/диск;
  • перенести тяжёлые объекты в отдельный tablespace, если архитектура это допускает.

Нехватка диска при обслуживании PostgreSQL: контроль свободного места и WAL

Что сделать, чтобы bloat возвращался реже

Перепаковка лечит симптом. Чтобы реже к ней возвращаться, обычно помогают:

  • тонкая настройка autovacuum под вашу нагрузку (пороги, частота, cost limit/delay);
  • корректный fillfactor для таблиц и индексов с частыми обновлениями;
  • партиционирование по времени/ключу, чтобы «выкидывать» старые данные без массовых DELETE;
  • регулярный мониторинг роста объектов и доли dead tuples;
  • периодический REINDEX для реально деградирующих индексов.

Если вы часто делаете массовые удаления в больших таблицах, почти всегда стоит подумать о партициях. Сброс партиции возвращает место намного дешевле по ресурсам, чем переписывание гигантской таблицы.

Минимальные команды: что запускать

Чтобы не путаться в терминах:

  • VACUUM — чистит мёртвые версии, место ОС обычно не возвращает.
  • VACUUM FULL — переписывает таблицу и возвращает место ОС, но блокирует.
  • REINDEX — перестраивает индексы (и может вернуть место, занятое индексом), но таблицу не уменьшает.
  • pg_repack — уплотняет таблицу/индексы почти онлайн, но требует диска и даёт нагрузку.
-- VACUUM FULL (опасно для продакшена без окна обслуживания)
VACUUM FULL VERBOSE public.big_table;
-- REINDEX конкретного индекса
REINDEX INDEX public.big_table_some_idx;
-- REINDEX таблицы (все её индексы)
REINDEX TABLE public.big_table;

Запуск pg_repack зависит от того, как он установлен и как устроен доступ к вашей базе, но общая идея всегда одна: выбрать объект, убедиться в наличии места, запустить операцию в подходящее окно и сравнить размер до/после.

Итог: как выбрать между pg_repack и VACUUM FULL

  • Нужен гарантированный возврат места и есть окно простоя — выбирайте VACUUM FULL (проще и предсказуемее).
  • Простоя быть не должно, таблица большая и активная — чаще выбирают pg_repack, но готовятся к нагрузке и требованиям по диску.
  • Проблема локально в индексах — начните с REINDEX, не трогая таблицу целиком.

В реальном продакшене «правильный» вариант почти всегда определяется тремя ограничениями: сколько у вас свободного диска, насколько критичны блокировки и какую нагрузку на I/O и WAL вы можете себе позволить.

Поделиться статьей

Вам будет интересно

SSL-сертификаты DV, OV и EV: в чём разница и что выбрать в 2025 OpenAI Статья написана AI (GPT 5)

SSL-сертификаты DV, OV и EV: в чём разница и что выбрать в 2025

DV, OV и EV — это уровни проверки перед выпуском TLS-сертификата. Разберём, что валидирует CA, как изменилось отображение в браузе ...
age vs GPG vs SOPS: чем шифровать секреты в DevOps и GitOps OpenAI Статья написана AI (GPT 5)

age vs GPG vs SOPS: чем шифровать секреты в DevOps и GitOps

Сравнение age, GPG и SOPS с позиции эксплуатации: модель ключей, онбординг и офбординг, GitOps и PR-диффы, CI/CD, ротация и частые ...
GitOps в Kubernetes: FluxCD vs Argo CD для continuous delivery OpenAI Статья написана AI (GPT 5)

GitOps в Kubernetes: FluxCD vs Argo CD для continuous delivery

Сравниваем FluxCD и Argo CD для GitOps в Kubernetes: философия, архитектура, подход к деплою, drift/diff, RBAC и multi-tenant, раб ...