Каждые пару месяцев кто-то приходит с фразой «таблица распухла, надо сделать VACUUM FULL». Почти всегда за этим стоит одно: autovacuum не успевает, потому что ему мешают настройки по умолчанию.
VACUUM FULL переписывает таблицу целиком и держит ACCESS EXCLUSIVE на всё время работы. На таблице в 40 ГБ это часы, в которые никто не пишет и не читает. И это лечит симптом, а не причину: через неделю раздувание вернётся.
Смотреть надо не на размер, а на мусор
SELECT relname,
n_live_tup,
n_dead_tup,
round(n_dead_tup::numeric / greatest(n_live_tup, 1) * 100, 2) AS dead_pct,
last_autovacuum
FROM pg_stat_user_tables
WHERE n_dead_tup > 10000
ORDER BY n_dead_tup DESC
LIMIT 20;
Если dead_pct держится выше 20%, а last_autovacuum недельной давности — проблема в том, что вакуум не доходит до таблицы, а не в том, что его мало.
Три настройки, которые обычно и виноваты
autovacuum_vacuum_scale_factor = 0.2. При дефолте вакуум приходит, когда мёртвых строк станет 20% от живых. Для таблицы в 10 миллионов строк это два миллиона — до этого момента место не освобождается. Ставим 0.02 для крупных таблиц.
autovacuum_max_workers = 3. Если в базе двести таблиц, три воркера физически не успевают обойти их все.
Долгие транзакции. Пока открыта транзакция, которая началась до мусора, вакуум не может его убрать. Одна забытая сессия в idle in transaction держит мусор во всей базе. Проверяется мгновенно:
SELECT pid, state, now() - xact_start AS dur, query
FROM pg_stat_activity
WHERE state <> 'idle' AND now() - xact_start > interval '5 minutes';
Когда VACUUM FULL всё-таки оправдан
Ровно два случая: таблица раздулась один раз и больше не растёт (архив), либо нужен переезд на другой tablespace. Во всех остальных случаях pg_repack делает то же самое без блокировки записи — и это единственный инструмент, который я держу под рукой для такой задачи.
Проверка простая: если вы не можете назвать причину раздувания, VACUUM FULL её не устранит.