Устранение разрастания таблиц и индексов в PostgreSQL: утилита pg_repack
- Таблица и ее индексы занимают сотни гигабайт на диске, хотя полезных данных в ней всего 10–20%.
- Замедление сканирования индексов (Index Scan) из-за разреженности страниц в B-Tree структурах.
- Невозможность выполнить
VACUUM FULLиз-за недопустимости монопольной блокировки таблицы в рабочее время 1С.
1. Установка расширения pg_repack
# Для Debian / Ubuntu (PostgreSQL 16)
apt-get install -y postgresql-16-repack
# Включение расширения внутри целевой базы
psql -d Enterprise1C -c "CREATE EXTENSION pg_repack;"2. Анализ разрастания (Bloat) таблиц и индексов
-- Проверка примерного процента мертвых страниц в индексах
SELECT
schemaname, tablename, indexname,
pg_size_pretty(pg_relation_size(indexrelid)) AS IndexSize
FROM pg_stat_user_indexes
ORDER BY pg_relation_size(indexrelid) DESC LIMIT 10;3. Запуск онлайн-дефрагментации через консоль
# Репак конкретной таблицы и всех ее индексов на лету
pg_repack -h 127.0.0.1 -p 5432 -U postgres -d Enterprise1C --table public._accumrgtn12345
# Репак только индексов всей базы данных в 4 параллельных потока
pg_repack -h 127.0.0.1 -p 5432 -U postgres -d Enterprise1C --only-indexes -j 44. Требования и проверка свободного дискового пространства
Для работы pg_repack на диске должно быть свободно не менее 100–120% от текущего размера обрабатываемой таблицы, так как утилита создает временную теневую копию таблицы и переносит данные через триггер логов изменений.
Частые вопросы (FAQ)
Как pg_repack выполняет перепаковку без длительной блокировки таблицы?
Он создает временную таблицу, копирует в нее существующие данные, параллельно собирает все новые входящие изменения (INSERT/UPDATE/DELETE) через триггер в таблицу журнала, накатывает их и в конце кратковременно берет блокировку AccessExclusiveLock на доли секунды только для подмены файлов в каталоге.
Обязательно ли наличие Primary Key или NOT NULL Unique индекса для pg_repack?
Да. Для перепаковки таблицы целиком pg_repack требует наличия первичного ключа (PRIMARY KEY) или уникального индекса с полями NOT NULL. Перепаковка только индексов (--only-indexes) работает без этого ограничения.
Что делать, если процесс pg_repack аварийно оборвался?
В базе могут остаться временные таблицы и триггеры в схеме repack. Удалите расширение DROP EXTENSION pg_repack CASCADE; и создайте его заново CREATE EXTENSION pg_repack;.
В чем отличие pg_repack от стандартной команды REINDEX CONCURRENTLY?
REINDEX CONCURRENTLY перестраивает только индексы без блокировок, но не может сжать и освободить место самого тела таблицы (Heap Bloat). pg_repack перестраивает как саму таблицу, так и все ее индексы.