lesson ── postgres-labs ── ~24 мин ── 6 шагов
Autovacuum невидим, пока не сломается. Сейчас мы вытащим его логику
наружу: посчитаем порог срабатывания по формуле, наплодим мусор, измерим
раздувание числом через pgstattuple и подкрутим scale_factor. Чтобы
замеры были честными, заведём свою таблицу с выключенным autovacuum -
тогда мусор никто не уберёт у нас из-под рук.
интерактивный sandbox
Поднимется контейнер postgreslab/postgres-base с PostgreSQL 17 и psql. В браузере откроется терминал, база lab уже настроена. Каждый шаг проверяется автоматически. Сеть air-gapped, наружу контейнер не ходит.
stack ── PostgreSQL 17 · psql · 1 GB RAM · air-gapped · самоуничтожается через 45 мин простоя
CREATE TABLE av_demo (id serial PRIMARY KEY, payload text)
WITH (autovacuum_enabled = false);
INSERT INTO av_demo (payload)
SELECT repeat('x', 200) FROM generate_series(1, 2000);Выключенный autovacuum гарантирует: мёртвые версии не исчезнут, пока мы сами не позовём VACUUM. Это нужно только для чистоты опыта.
✓ Таблица готова, autovacuum для неё отключён.
Autovacuum сработал бы, когда мёртвых версий станет больше порога
threshold + scale_factor × reltuples. Посчитаем его и сравним с
числом мёртвых версий:
SELECT n_dead_tup,
50 + 0.2 * reltuples AS av_threshold
FROM pg_stat_all_tables s
JOIN pg_class c ON c.relname = s.relname
WHERE s.relname = 'av_demo';
Пока таблицу только заполнили - мёртвых версий нет, порог не взят.
✓ Порог посчитан — теперь видно, сколько мусора нужно для срабатывания.
UPDATE av_demo SET payload = repeat('y', 200);SELECT dead_tuple_count FROM pgstattuple('av_demo');Обновили все 2000 строк - столько же версий стали мёртвыми. Это намного больше порога (около 450). Будь autovacuum включён, он бы уже встал в очередь.
✓ Порог перейдён — мусора больше, чем нужно для автоочистки.
SELECT tuple_percent, dead_tuple_percent, free_percent
FROM pgstattuple('av_demo');pgstattuple сканирует таблицу и считает доли. Высокий
dead_tuple_percent - то самое раздувание. На большой таблице такой
полный скан дорог, там берут pgstattuple_approx.
✓ Раздувание измерено числом, а не на глаз.
Горячей таблице нужен агрессивный autovacuum. Снизим scale_factor
и снова его включим:
ALTER TABLE av_demo SET (
autovacuum_vacuum_scale_factor = 0.01,
autovacuum_enabled = true
);
SELECT reloptions FROM pg_class WHERE relname = 'av_demo';
Теперь порог - 1% от размера вместо 20%. Так настраивают крупные и часто обновляемые таблицы индивидуально.
✓ scale_factor=0.01 — autovacuum будет чистить таблицу куда раньше.
SELECT pg_relation_size('av_demo') AS size_before;VACUUM av_demo;
SELECT dead_tuple_count FROM pgstattuple('av_demo');SELECT pg_relation_size('av_demo') AS size_after;Обычный VACUUM убрал мёртвые версии (dead_tuple_count упал до нуля),
но размер файла не уменьшился - место освободилось внутри под будущие
вставки. Вернуть его ОС умеет только VACUUM FULL.
Горизонт ничто не держит, поэтому VACUUM уберёт весь мусор.
✓ Мусор убран, но файл прежнего размера — классическое поведение VACUUM.
Autovacuum срабатывает по порогу threshold + scale_factor × reltuples. Раздувание измеряют через pgstattuple. scale_factor 0.2 велик для больших таблиц - им задают индивидуальный порог. Обычный VACUUM не уменьшает файл.
команды
SELECT n_dead_tup, 50 + 0.2*reltuples FROM pg_stat_all_tables JOIN pg_class USING(relname) WHERE relname='av_demo';порог autovacuumSELECT dead_tuple_percent, free_percent FROM pgstattuple('av_demo');раздувание числомALTER TABLE av_demo SET (autovacuum_vacuum_scale_factor = 0.01);агрессивный autovacuum для горячей таблицыконцепции