MVCC (Multi-Version Concurrency Control)
- При
UPDATEилиDELETEстарая версия строки (tuple) не удаляется физически. - Она помечается как «мёртвая» (
t_xmax = XID_удалившей_транзакции). - Новые транзакции её не видят, но она остаётся на диске.
Проблема: со временем таблица раздувается (bloat) → растёт размер на диске, замедляются сканирования.
VACUUM - находит мёртвые tuple’ы и помечает их пространство как свободное для повторного использования.
VACUUM
1. Сканирует таблицу постранично
- Читает каждую 8 КБ-страницу таблицы (heap).
- Для каждой страницы:
- Проверяет каждый tuple.
- Определяет, жив ли он с точки зрения текущего snapshot’а и
oldestXmin.
2. Определяет, какие tuple’ы можно удалить
Tuple считается мёртвым и подлежащим очистке, если:
t_xmax ≠ 0(был удалён/обновлён),- И транзакция
t_xmaxзавершена, - И никакая активная транзакция не может его видеть (т.е.
t_xmax < oldestXmin).
oldestXmin— это самый старый XID среди всех активных транзакций в кластере (берётся изProcArray).
3. Помечает мёртвые tuple’ы как свободное пространство
- Внутри страницы:
- Удаляет указатели на мёртвые tuple’ы из line pointer array.
- Обновляет free space map (FSM) — карту свободного места.
- Физически данные не стираются, но пространство становится доступным для новых строк.
FSM — Free Space Map (Карта свободного места)
- Битовая/байтовая карта, которая показывает, сколько свободного места есть на каждой странице таблицы или индекса.
- Позволяет PostgreSQL быстро найти страницу с достаточным местом для вставки новой строки — без сканирования всей таблицы.
Где хранится?
Отдельный файл рядом с таблицей:
12345_fsm(где12345— RELFILENODE таблицы).В памяти: кэшируется в
shared_buffers.Обновляется при
INSERT,UPDATE,DELETEиVACUUM.Не хранит точное расположение свободного места — только объём.
Если FSM повреждена — PostgreSQL перестраивает её автоматически.
если видите частые «heap page full» в логах — возможно, FSM не успевает обновляться (редко, но бывает при экстремальной нагрузке).
4. Обновляет служебные структуры
- Visibility Map (VM):
- Если вся страница содержит только видимые для всех строки, устанавливает бит «all-visible».
- Это позволяет пропускать страницу при будущих VACUUM’ах и ускоряет
VACUUMиSELECT.
- Статистика:
- Обновляет счётчики в
pg_stat_user_tables:n_dead_tup,n_live_tup.
- Обновляет счётчики в
Visibility Map — (Карта видимости) - Битовая карта, где каждый бит соответствует одной странице таблицы.
Бит = 1, если все строки на этой странице видимы для всех транзакций (т.е. нет мёртвых или невидимых строк).
- Ускоряет
VACUUM: - Если бит = 1,VACUUMпропускает эту страницу — не нужно читать её содержимое.- Ускоряет
SELECTприindex-only scan:
- Если индекс содержит все нужные колонки и страница помечена как «all-visible»,
→ PostgreSQL не читает саму таблицу (heap), а берёт данные только из индекса.Где хранится?
- Отдельный файл:
12345_vm- Также кэшируется в
shared_buffers.Как обновляется?
- При
VACUUM— устанавливает бит в 1, если страница полностью видима.- При
UPDATE/DELETE— сбрасывает бит в 0, потому что на странице появилась невидимая строка.
В production почти всегда используется обычный
VACUUM.
VACUUM FULL— только для экстренных случаев (огромный bloat, нехватка диска).
VACUUM — это “уборщик мусора” MVCC, который:
- Находит мёртвые версии строк,
- Помечает их место как свободное,
- Обновляет служебные карты (FSM, VM),
- Позволяет PostgreSQL повторно использовать место внутри файлов,
- Не блокирует работу приложения (в обычном режиме).
autoVACUUM
PostgreSQL автоматически запускает VACUUM через Autovacuum:
- Autovacuum Launcher — следит за таблицами.
- Autovacuum Worker — выполняет
VACUUMиANALYZE.
Запускается по формуле
мёртвые_строки ≥ autovacuum_vacuum_threshold + (autovacuum_vacuum_scale_factor * общее_число_строк)
# Пример: в таблице 10 000 строк → `VACUUM` запустится при ~2050 мёртвых строк.
# Когда именно autovacuum решит, что таблица нуждается в очистке мёртвых строк
autovacuum_vacuum_threshold = 50
# Обсолютный минимум мёртвых строк, при котором может сработать `VACUUM`. Гарантирует, что даже очень маленькие таблицы будут очищаться.
# Позволяет масштабировать порог под размер таблицы
autovacuum_vacuum_scale_factor = 0.2
# Доля от общего числа строк, которая добавляется к порогу.
# Позволяет масштабировать порог под размер таблицы.
# Живых строк Порог мёртвых строк
# Маленькая 1 000 `50 + 0.2 × 1000 = 250`
# Средняя 100 000 `50 + 0.2 × 100 000 = 20 050`
# Большая 10 000 000 `50 + 0.2 × 10 000 000 = 2 000 050`
# тем реже запускается `VACUUM`, но больше строк очищается за раз
Проверить текущие значения:
-- Глобальные настройки
SHOW autovacuum_vacuum_scale_factor;
SHOW autovacuum_vacuum_threshold;
-- Для конкретной таблицы
SELECT relname,
reloptions
FROM pg_class
WHERE relname = 'orders';По умолчанию:
autovacuum_vacuum_threshold = 50autovacuum_vacuum_scale_factor = 0.2(20%)
-- Как проверить, что VACUUM работает?
-- Статистика по таблицам
SELECT schemaname, tablename,
n_tup_ins, n_tup_upd, n_tup_del,
n_dead_tup,
last_autovacuum
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC;
-- Прогресс выполнения VACUUM
SELECT * FROM pg_stat_progress_vacuum;