Почему база данных выросла после VACUUM FULL и как исправить
Ситуация, когда после выполнения VACUUM FULL ANALYZE размер базы данных увеличивается вместо уменьшения, встречается на практике. В одном из проектов объём БД вырос с 1,4 ТБ до 2 ТБ. При этом дамп и восстановление на другом сервере возвращали нормальный размер 1,4 ТБ. Разберёмся, что произошло и как найти «потерянное» место.
Почему VACUUM FULL увеличивает базу данных
Операция VACUUM FULL перестраивает таблицы и индексы, создавая новые файлы данных. В процессе: старые файлы не удаляются сразу, пока не завершится перезапись; создаются временные копии .tmp; при снятии снимка виртуальной машины файловая система фиксирует состояние «до завершения». Если в этот момент сделать снапшот, новые файлы остаются, а старые - не удаляются, так как ссылки на них ещё активны.
Основные причины роста на 30-40%
- Снапшот во время VACUUM FULL - виртуальная машина «заморозила» процесс, и файлы не были очищены.
- Временные файлы и WAL-журналы - хотя вы исключили временные файлы, стоит проверить
pg_walи архивы. - «Мёртвые» строки и TOAST-таблицы - после сбоя часть старых версий строк могла остаться в системных таблицах.
Как определить, что именно занимает место
Чтобы найти «лишние» гигабайты, выполните диагностику на уровне файловой системы и внутри PostgreSQL.
1. Проверьте каталог данных
Зайдите на сервер и выполните:
du -sh /var/lib/postgresql/*/base/*/Сравните размеры баз данных с ожидаемыми. Если какая-то база весит больше, чем сумма её таблиц - проблема в файлах, не привязанных к объектам.
2. Исключите WAL и архивы
Проверьте размер pg_wal:
du -sh /var/lib/postgresql/*/pg_wal/Если он превышает несколько гигабайт, настройте wal_keep_segments или архивацию.
3. Найдите потерянные файлы
В каталоге base/ могут лежать файлы, не соответствующие ни одной таблице. Используйте запрос:
SELECT oid, relname, relfilenode FROM pg_class WHERE relfilenode > 0;Сравните список relfilenode с файлами в base/<db_oid>/. Файлы, которых нет в выводе - «осиротевшие».
4. Проверьте TOAST-таблицы
TOAST может хранить большие объёмы данных. Запрос:
SELECT relname, pg_size_pretty(pg_total_relation_size(oid)) FROM pg_class WHERE reltoastrelid > 0;Если TOAST-таблица весит неожиданно много - выполните VACUUM FULL для неё отдельно.
Как вернуть базу к нормальному размеру
Если вы нашли «осиротевшие» файлы, самый надёжный способ - сделать pg_dump и восстановить на новом сервере. Это гарантированно уберёт весь мусор. Альтернатива - удалить лишние файлы вручную (только если уверены, что они не нужны).
Что делать, чтобы избежать повторения
- Не делайте снапшоты ВМ во время
VACUUM FULLили других операций, переписывающих файлы. - Используйте
VACUUM(без FULL) для регулярной очистки. - Настройте мониторинг размера каталога
base/иpg_wal.
В описанном кейсе проблема решилась дампом и восстановлением - размер вернулся к 1,4 ТБ. После этого настроили автоматический VACUUM и запретили снапшоты во время обслуживания.