Заметки о VACUUM в PostgreSQL
Таблица событий у нас занимала на диске в четыре раза больше, чем весили сами данные. Запросы к ней медленно деградировали, хотя количество строк почти не менялось. Классическая картина раздувания, и разбираться с ней пришлось всерьёз.
Откуда берутся мёртвые строки
PostgreSQL не перезаписывает строку при обновлении: он создаёт новую версию, а старая остаётся на месте, пока её могут видеть открытые транзакции. Удаление работает так же. Освобождает место только VACUUM, и если он не успевает за потоком изменений, таблица растёт.
Как увидеть проблему
Начинать стоит со статистики: она показывает, сколько мёртвых строк накопилось и когда autovacuum в последний раз доходил до таблицы.
SELECT relname, n_live_tup, n_dead_tup, last_autovacuum
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC
LIMIT 10;
У нас в первой строке оказалась та самая таблица событий: десятки миллионов мёртвых строк и последний autovacuum три дня назад.
Что мы поменяли
- Для больших и часто меняющихся таблиц понизили порог срабатывания. Значение по умолчанию — двадцать процентов изменённых строк, для таблицы в сто миллионов строк это слишком редко.
- Подняли лимит стоимости, чтобы autovacuum работал быстрее: дисков хватает, а очередь за ним росла.
- Нашли и закрыли долгие транзакции. Одна забытая сессия в состоянии
idle in transactionмешает очистке во всей базе.
ALTER TABLE events SET (autovacuum_vacuum_scale_factor = 0.02);
Чего делать не стоит
Не отключайте autovacuum «на время миграции» и не запускайте VACUUM FULL на рабочей базе в разгар дня: он берёт эксклюзивную блокировку. Если таблицу нужно ужать без простоя, есть инструменты, которые перестраивают её онлайн.