PostgreSQL VACUUM: autovacuum и раздутые таблицы
Коротко: PostgreSQL не удаляет строки сразу, а помечает их; VACUUM очищает, освобождает место для повторного использования и поддерживает статистику актуальной, обычно автоматически через autovacuum.
Подробнее: Из-за MVCC (несколько версий строки для параллельных транзакций) UPDATE и DELETE порождают мёртвые кортежи. Они остаются, пока никакой выполняющийся доступ в них больше не нуждается. VACUUM убирает их с точки зрения повторного использования.
Подробности
Что делает VACUUM
- Помечает место мёртвых строк как доступное для повторного использования.
- Обновляет карту видимости (ускоряет index-only-сканирования).
- Защищает от переполнения идентификатора транзакции (wraparound) (замораживает старые строки).
- VACUUM FULL перезаписывает таблицу и возвращает место операционной системе, но блокирует монопольно; нужен редко (альтернатива:
pg_repack). - ANALYZE собирает статистику для планировщика запросов.
Autovacuum
Фоновый процесс запускает VACUUM/ANALYZE, когда накопилось достаточно изменений (по умолчанию: 20 % таблицы + 50 строк). Настройки: autovacuum_vacuum_scale_factor, autovacuum_naptime, для отдельной таблицы ALTER TABLE … SET (autovacuum_vacuum_scale_factor = 0.02). Никогда не отключайте. Для больших, сильно изменяемых таблиц настраивайте агрессивнее.
Выявление раздувания (bloat)
Симптомы: таблица/индекс растёт при том же объёме данных, запросы замедляются. Проверка: pg_stat_user_tables (n_dead_tup, last_autovacuum), размер через pg_total_relation_size, расширение pgstattuple. Причины: длинные транзакции или забытые открытые соединения (мешают очистке), слишком редкий autovacuum, частые массовые обновления. Решение: держать транзакции короткими, тоньше настроить autovacuum, вручную VACUUM (VERBOSE, ANALYZE) table;.
Практика и управляемые сервисы
В Neon, Supabase, RDS autovacuum в основном работает автоматически; всё же наблюдайте за шаблонами (таблицы с множеством обновлений вроде сеансов, счётчиков, очередей: лучше вставка + удаление старых строк или партиции). Удаляйте большие объёмы пакетами. Делайте резервную копию перед VACUUM FULL. Читайте pg_stat_progress_vacuum. Соединения, застрявшие в idle in transaction, — враг любого vacuum: ограничивайте через idle_in_transaction_session_timeout.
См. также: PostgreSQL, MVCC и уровни изоляции, Индексы PostgreSQL, Пулинг соединений