# Autovacuum: пороги и bloat _Vacuum, freeze, wraparound · PostgreSQL Knowledge Base_ **TL;DR:** Autovacuum чистит таблицу, когда мёртвых версий накопится больше порога threshold + scale_factor × reltuples (50 и 0.2 по умолчанию). scale_factor 0.2 плохо масштабируется на большие таблицы, поэтому горячим задают индивидуальные пороги. autovacuum=off ведёт к bloat и wraparound. ## Формула срабатывания ``` порог = autovacuum_vacuum_threshold + autovacuum_vacuum_scale_factor × reltuples ``` По умолчанию `threshold = 50`, `scale_factor = 0.2`: уборка запускается, когда `n_dead_tup` превысит 50 + 20% от числа живых строк. Для миллиона строк это больше 200 тысяч мёртвых версий. ```sql SELECT relname, n_live_tup, n_dead_tup, 50 + 0.2 * n_live_tup AS av_threshold FROM pg_stat_all_tables WHERE relname = 'bloat_demo'; ``` ## Почему 0.2 плох для больших таблиц Порог пропорционален размеру. 20% от 100 млн строк - это 20 млн мёртвых версий, которые лежат раздутым грузом между уборками. Поэтому крупным и горячим таблицам задают индивидуальный, меньший порог: ```sql ALTER TABLE big_events SET ( autovacuum_vacuum_scale_factor = 0.02, autovacuum_vacuum_threshold = 1000 ); ``` Настройка таблицы переопределяет глобальную. Один общий `scale_factor` почти никогда не оптимален. ## Порог по вставкам (PG13+) Append-only таблицы не создают мёртвых версий, и раньше autovacuum их не трогал - страдали index-only сканы и заморозка. С PostgreSQL 13 есть отдельный порог `autovacuum_vacuum_insert_threshold` (1000) + `autovacuum_vacuum_insert_scale_factor` (0.2), и такие таблицы тоже регулярно проходят VACUUM. ## Bloat и его измерение Раздувание - место под мёртвыми версиями и пустотами; симптом того, что VACUUM не поспевает. Измеряют через `pgstattuple` (`dead_tuple_percent`, `free_percent`); на больших таблицах берут `pgstattuple_approx` из-за полного скана. Вернуть место ОС умеет только `VACUUM FULL` или `pg_repack` (см. [vacuum](/courses/postgres/kb/vacuum.md)). ## Поймать за работой ```sql SELECT relname, last_autovacuum, autovacuum_count FROM pg_stat_all_tables WHERE relname = 'bloat_demo'; SELECT relid::regclass, phase, heap_blks_scanned, heap_blks_total FROM pg_stat_progress_vacuum; ``` ## autovacuum=off — дорогая ошибка Отключение останавливает уборку (растёт bloat) и заморозку (возраст ползёт к 200 млн, см. [wraparound](/courses/postgres/kb/wraparound.md)). Анти-wraparound autovacuum всё равно сработает, но как аврал на пике. Правильная реакция на «autovacuum мешает» - сделать его агрессивнее (больше воркеров, меньше `cost_delay`, индивидуальные пороги), а не выключать. ## Команды ```sql ALTER TABLE big_events SET (autovacuum_vacuum_scale_factor = 0.02); ``` Чистить горячую таблицу при 2% мусора вместо 20% ```sql SELECT * FROM pg_stat_progress_vacuum; ``` Что делает текущий проход VACUUM прямо сейчас ```sql SELECT relname, last_autovacuum FROM pg_stat_all_tables ORDER BY last_autovacuum; ``` Когда таблицы чистились в последний раз ## См. также - [VACUUM и removable cutoff](/courses/postgres/kb/vacuum.md) - [Горизонт транзакции](/courses/postgres/kb/transaction-horizon.md) - [Wraparound и колесо XID](/courses/postgres/kb/wraparound.md) - [HOT-обновления и fillfactor](/courses/postgres/kb/hot-updates.md)