Зачем нужна, если есть VACUUM
VACUUM проходит таблицу целиком и чистит индексы - это дорого и нечасто. Но страница с длинной HOT-цепочкой переполняется задолго до следующего VACUUM. Внутристраничная очистка (prune) решает локальную задачу: убрать мёртвые версии в пределах одной страницы прямо сейчас, чтобы освободить место под новые версии.
Prune запускается оппортунистически - когда страницу и так читают или пишут, а PostgreSQL видит, что она забита мёртвыми версиями. Отдельного процесса для prune нет: он встроен в обычные обращения к странице.
Что он делает и чего не делает
- убирает версии, не видимые ни одному снимку, освобождая место в странице;
- укорачивает HOT-цепочки, перестраивая line pointers;
- не трогает индексы - это его принципиальное ограничение.
Поскольку prune не может вычистить индексные ссылки, он не удаляет указатель, на который может ссылаться индекс. Вместо этого корень HOT-цепочки превращается в redirect.
lp_flags: статусы указателя
Состояние line pointer видно через pageinspect:
| lp_flags | имя | значение |
|---|---|---|
| 0 | LP_UNUSED | указатель свободен, переиспользуем |
| 1 | LP_NORMAL | ведёт к обычной версии строки |
| 2 | LP_REDIRECT | перенаправляет на другой указатель (след HOT) |
| 3 | LP_DEAD | мёртвый, ждёт очистки индексов через VACUUM |
SELECT lp, lp_flags, t_ctid
FROM heap_page_items(get_raw_page('acc', 0));LP_REDIRECT - это и есть результат prune: корень цепочки сохранён как
точка входа для индекса, но перенаправляет на актуальную версию.
LP_DEAD - указатель, который prune пометил мёртвым, но окончательно
освободит только VACUUM, предварительно убрав ссылки из индексов.
Связь с HOT
Prune и HOT - две стороны одного механизма. HOT-обновления складывают версии в цепочку внутри страницы (см. hot-updates), а prune эту цепочку подчищает, не давая ей переполнить страницу. Вместе они откладывают необходимость полноценного vacuum, но не отменяют его.