mmmnetwork

Технические заметки небольшой команды

· 9 мин чтения

Заметки о 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 на рабочей базе в разгар дня: он берёт эксклюзивную блокировку. Если таблицу нужно ужать без простоя, есть инструменты, которые перестраивают её онлайн.