Что такое vacuum в PostgreSQL и зачем он нужен?
VACUUM в PostgreSQL убирает «мёртвые» кортежи, оставшиеся от MVCC, освобождает место для повторного использования и предотвращает Transaction ID Wraparound. Autovacuum запускается автоматически при превышении порога dead tuples (по умолчанию 20% строк).
Что такое VACUUM
PostgreSQL использует MVCC (Multi-Version Concurrency Control) для изоляции транзакций: вместо изменения строки на месте создаётся новая версия, а старая помечается как «мёртвая» (dead tuple). VACUUM убирает мёртвые кортежи и освобождает место для повторного использования. Без регулярного VACUUM таблицы раздуваются (bloat), а при переполнении счётчика транзакций грозит Transaction ID Wraparound.
Типы VACUUM
-- Стандартный VACUUM: помечает мёртвые кортежи как доступные для повторного использования
-- НЕ возвращает место ОС, НЕ блокирует таблицу на чтение/запись
VACUUM users;
-- VACUUM ANALYZE: убирает мёртвые кортежи + обновляет статистику планировщика
VACUUM ANALYZE users;
-- VACUUM FULL: дефрагментирует таблицу и возвращает место ОС
-- БЛОКИРУЕТ таблицу на всё время (аналог REWRITE TABLE)
-- Используйте только при критичном bloat и возможности простоя
VACUUM FULL users;
-- VACUUM VERBOSE: подробный вывод о проделанной работе
VACUUM (VERBOSE, ANALYZE) users;
-- VACUUM FREEZE: заморозить транзакционные ID (предотвратить wraparound)
VACUUM FREEZE users;
Autovacuum
Autovacuum — фоновый процесс, запускающий VACUUM автоматически при достижении порога мёртвых кортежей. Настраивается глобально в postgresql.conf и per-table.
-- Глобальные настройки autovacuum
-- postgresql.conf:
-- autovacuum = on
-- autovacuum_vacuum_scale_factor = 0.2 # 20% мёртвых кортежей = триггер
-- autovacuum_analyze_scale_factor = 0.1 # 10% = триггер для ANALYZE
-- autovacuum_vacuum_threshold = 50 # минимум 50 строк
-- Per-table настройки для высоконагруженных таблиц
ALTER TABLE events SET (
autovacuum_vacuum_scale_factor = 0.01, -- 1% (не 20%)
autovacuum_vacuum_threshold = 100,
autovacuum_analyze_scale_factor = 0.005
);
-- Проверить текущие настройки таблицы
SELECT relname, reloptions
FROM pg_class
WHERE relname = 'events';
Мониторинг VACUUM
-- Состояние таблиц: мёртвые кортежи, последний VACUUM
SELECT
schemaname,
relname,
n_dead_tup,
n_live_tup,
ROUND(100.0 * n_dead_tup / NULLIF(n_live_tup + n_dead_tup, 0), 2) AS dead_pct,
last_vacuum,
last_autovacuum,
last_analyze
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC
LIMIT 20;
-- Таблицы с риском Transaction ID Wraparound
SELECT
relname,
age(relfrozenxid) AS xid_age,
2147483647 - age(relfrozenxid) AS xids_left
FROM pg_class
WHERE relkind = 'r'
ORDER BY age(relfrozenxid) DESC
LIMIT 10;
-- Если xid_age > 2 млрд — PostgreSQL уйдёт в аварийный режим!
Transaction ID Wraparound
PostgreSQL использует 32-битный счётчик транзакций. При переполнении (wraparound) все данные стали бы «из будущего» и невидимы. Для предотвращения: autovacuum FREEZE замораживает старые строки. Признак близкого wraparound: age(relfrozenxid) > 1.5 млрд.
-- Принудительная заморозка при высоком age
VACUUM FREEZE ANALYZE critical_table;
-- В postgresql.conf: агрессивная заморозка начинается при
-- autovacuum_freeze_max_age = 200000000 (200 млн)
Подводные камни
- VACUUM FULL — это REWRITE TABLE с эксклюзивной блокировкой. Для production без downtime используйте pg_repack или pg_squeeze.
- Долгая транзакция (idle in transaction) блокирует autovacuum от удаления мёртвых кортежей — всегда мониторьте
pg_stat_activity WHERE state = 'idle in transaction'. - Autovacuum по умолчанию ограничен в ресурсах (
autovacuum_vacuum_cost_delay) и может не справляться с высоконагруженными таблицами — увеличьтеautovacuum_max_workersи уменьшите cost delay. - Repacked таблица требует свободного места размером с текущую таблицу — следите за дисковым пространством перед VACUUM FULL или pg_repack.
- Статистика планировщика не обновляется без ANALYZE — VACUUM без ANALYZE не помогает производительности запросов.
- Transaction ID Wraparound может случиться даже при включённом autovacuum, если на таблице есть репликационный слот без активного standby или долгая транзакция.
- VACUUM не работает с foreign tables и некоторыми типами партиционированных таблиц без явного указания секции.
Common mistakes
- Отвечать про vacuum как про абстрактный SQL без учета MVCC, WAL, planner или конкретной версии PostgreSQL.
- Переносить поведение MySQL или ClickHouse на PostgreSQL без проверки документации.
- Не связывать механизм с последствиями для индексов, транзакций, блокировок или эксплуатации.
- Показывать синтаксис, который не поддерживается PostgreSQL.
What the interviewer is testing
- Кандидат объясняет vacuum через реальный механизм PostgreSQL, а не общими словами.
- Приводит корректный SQL или диагностический запрос для этой СУБД.
- Называет ограничения, версионные отличия или эксплуатационные последствия.
- Связывает ответ с проектированием приложения, производительностью, надежностью или безопасностью.