PostgreSQL: медленный VACUUM — причины и решение
База пухнет, запросы замедляются, а очистка тянется вечно: PostgreSQL медленный VACUUM. VACUUM — это уборка мёртвых версий строк, которые PostgreSQL создаёт при каждом UPDATE и DELETE. Если он не успевает, таблицы раздуваются (bloat), и всё замедляется по кругу. Причина медленного вакуума почти всегда в настройках, мешающих транзакциях или нехватке ресурсов. Разберём, как ускорить очистку и разорвать порочный круг.
Содержание
- Первое действие: оцените bloat и активность автовакуума
- Причина 1: слишком консервативные настройки автовакуума
- Причина 2: долгие транзакции держат мёртвые строки
- Причина 3: таблица уже сильно раздута
- Причина 4: нехватка ресурсов и медленный диск
- Как убедиться, что вакуум догнал базу
- Профилактика: чтобы вакуум успевал всегда
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Первое действие: оцените bloat и активность автовакуума
Сначала поймите масштаб проблемы: сильно ли раздуты таблицы и работает ли автовакуум вообще. Посмотрите статистику по таблицам:
SELECT relname, n_dead_tup, n_live_tup, last_autovacuum
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC LIMIT 10;
Колонка n_dead_tup — число мёртвых строк, last_autovacuum — когда таблицу последний раз чистили. Если мёртвых строк много, а last_autovacuum пустой или очень старый — автовакуум не справляется или не запускается по этой таблице. Большое отношение мёртвых строк к живым означает bloat: таблица занимает намного больше места, чем нужно, и запросы по ней замедляются. Это отправная точка: вы видите, какие таблицы страдают и работает ли уборка. Дальше — почему она медленная.
Причина 1: слишком консервативные настройки автовакуума
Дефолтные настройки автовакуума рассчитаны на скромные серверы и часто слишком мягкие для нагруженной базы: он запускается редко и работает медленно, чтобы не мешать. На активной базе это приводит к отставанию. Ключевые параметры — порог запуска и «стоимостная задержка», которая специально тормозит вакуум. Проверьте их:
SHOW autovacuum_vacuum_scale_factor;
SHOW autovacuum_vacuum_cost_delay;
autovacuum_vacuum_scale_factor по умолчанию 0.2 означает, что вакуум ждёт, пока умрёт 20% строк таблицы — для большой таблицы это огромный объём. Уменьшите его (например, до 0.05) глобально или для конкретных горячих таблиц. autovacuum_vacuum_cost_delay искусственно замедляет вакуум ради щадящей нагрузки; на сервере с запасом ресурсов его снижают, а autovacuum_max_workers при необходимости увеличивают. Эти правки заставляют автовакуум запускаться чаще и работать быстрее. Настройка автовакуума под реальную нагрузку — главный рычаг против медленной очистки и bloat.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.
Арендовать VPS под базуПричина 2: долгие транзакции держат мёртвые строки
Это самая коварная причина: VACUUM физически не может удалить мёртвые строки, которые ещё «видны» какой-то старой открытой транзакции. Одна длинная транзакция или зависшая сессия idle in transaction блокирует очистку по всей базе — мёртвые строки копятся, вакуум работает, но освободить ничего не может. Найдите самые старые транзакции:
SELECT pid, state, xact_start, now()-xact_start AS age, query
FROM pg_stat_activity WHERE state <> 'idle'
ORDER BY xact_start LIMIT 5;
Транзакция, висящая часами, — вероятный виновник. Также проверьте забытые сессии в состоянии idle in transaction. Завершите зависшую транзакцию и почините приложение, чтобы оно не оставляло их открытыми; включите idle_in_transaction_session_timeout для автоматического обрыва. Пока живёт старая транзакция, никакие настройки вакуума не помогут — он просто не имеет права удалить строки. Поэтому при жалобах на bloat и медленную очистку всегда проверяйте долгие транзакции в первую очередь наряду с настройками.
Причина 3: таблица уже сильно раздута
Если bloat уже накопился, обычный VACUUM освобождает место для переиспользования внутри таблицы, но не отдаёт его операционной системе — файл таблицы остаётся большим. Чтобы физически сжать раздутую таблицу и вернуть место на диск, нужен более тяжёлый инструмент. Классический VACUUM FULL пересоздаёт таблицу, но берёт эксклюзивную блокировку и на время делает таблицу недоступной:
VACUUM FULL verbose имя_таблицы;
На боевой базе блокировка всей таблицы часто неприемлема, поэтому для онлайн-сжатия без долгой блокировки используют расширение pg_repack, которое пересобирает таблицу, почти не мешая работе. VACUUM FULL уместен в окно обслуживания или на некритичных таблицах. Важно понимать разницу: обычный (авто)вакуум предотвращает раздувание и поддерживает форму, а VACUUM FULL/pg_repack лечат уже случившийся bloat. Сначала устраните причину отставания вакуума, потом разово сожмите раздутые таблицы — иначе они распухнут снова.
Причина 4: нехватка ресурсов и медленный диск
VACUUM активно читает и пишет, поэтому на медленном диске или перегруженном сервере он естественно тянется долго. Если автовакуум настроен агрессивно, но всё равно не успевает, а диск загружен под завязку — узкое место в железе. Посмотрите нагрузку на диск во время вакуума:
iostat -x 5 3
Высокая утилизация диска (близко к 100%) во время очистки означает, что вакуум упирается в скорость накопителя. Здесь помогает быстрый NVMe-диск, увеличение maintenance_work_mem (память, которую вакуум использует для работы, — её увеличение ускоряет очистку индексов) и в целом достаточные ресурсы сервера. Параметр стоит поднять для операций обслуживания:
SHOW maintenance_work_mem;
Если база выросла, а сервер остался прежним, вакуум будет отставать просто от нехватки мощности. Тогда, устранив все программные причины, разумно добавить памяти и перейти на быстрый диск.
Как убедиться, что вакуум догнал базу
После правок проверьте, что число мёртвых строк снижается, а таблицы чистятся регулярно. Запустите ручной вакуум по проблемной таблице и снова посмотрите статистику:
VACUUM (VERBOSE, ANALYZE) имя_таблицы;
VERBOSE покажет, сколько строк убрано, а повторный запрос к pg_stat_user_tables должен показать свежий last_autovacuum и упавший n_dead_tup. Если мёртвые строки перестали накапливаться, а last_autovacuum обновляется регулярно — вакуум догнал базу. Не забудьте про ANALYZE: он обновляет статистику планировщика, без свежей статистики запросы могут выбирать плохие планы. Регулярный контроль этих метрик показывает, что уборка идёт в ногу с нагрузкой, а не отстаёт.
Профилактика: чтобы вакуум успевал всегда
Здоровье PostgreSQL напрямую зависит от того, успевает ли вакуум. Настройте автовакуум под реальную нагрузку — на активных таблицах уменьшите scale_factor, при ресурсах снизьте cost_delay, добавьте воркеров. Боритесь с долгими транзакциями: включите idle_in_transaction_session_timeout и следите, чтобы приложение закрывало транзакции вовремя — это половина всех проблем с вакуумом. Мониторьте n_dead_tup и last_autovacuum по ключевым таблицам, чтобы ловить отставание заранее.
Раздутые таблицы разово сжимайте через pg_repack в рабочем режиме или VACUUM FULL в окно обслуживания, но только после устранения причины отставания. И обеспечьте базе достаточные ресурсы — память под maintenance_work_mem и быстрый диск: вакуум любит и то, и другое. Настроенный автовакуум, отсутствие долгих транзакций и адекватное железо вместе держат базу компактной и быстрой, а «медленный VACUUM» перестаёт быть темой для тревоги.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.
Арендовать VPS под базуОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Почему автовакуум не успевает за базой?
Обычно из-за слишком мягких дефолтных настроек (scale_factor 0.2, ненулевой cost_delay) на нагруженной базе или из-за долгих транзакций, которые не дают удалять мёртвые строки. Проверьте и то, и другое.
Чем VACUUM отличается от VACUUM FULL?
Обычный вакуум освобождает место для переиспользования внутри таблицы и не блокирует её; VACUUM FULL физически пересоздаёт таблицу и возвращает место ОС, но берёт эксклюзивную блокировку. Для онлайна используйте pg_repack.
Почему VACUUM не удаляет мёртвые строки?
Скорее всего есть старая открытая транзакция, которой эти строки ещё «видны». Пока она живёт, вакуум не имеет права их убрать. Найдите и завершите долгие транзакции.
Как оплатить сервер с быстрым диском из России?
В MAATRIX — картой российского банка, через СБП, криптовалютой или токеном MAAT. Иностранная карта не нужна.
Нужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.