# Заморозка и relfrozenxid _Vacuum, freeze, wraparound · PostgreSQL Knowledge Base_ **TL;DR:** Заморозка помечает старую версию как видимую всем безусловно (бит HEAP_XMIN_FROZEN), выводя её из круговых сравнений и защищая от wraparound. relfrozenxid - граница заморозки таблицы; age(relfrozenxid) показывает её возраст в транзакциях. ## Зачем Идентификаторы транзакций - 32-битные и идут по кругу (см. [wraparound](/courses/postgres/kb/wraparound.md)). Версия, чей `xmin` отстал больше чем на ~2 млрд, «переворачивается» в будущее и становится невидимой. Чтобы этого не случилось, старые версии замораживают: помечают как видимые всем и навсегда выводят из сравнений. ## Как устроена Исторически заморозка переписывала `xmin` в FrozenTransactionId (число 2). Современный PostgreSQL не трогает `xmin`, а выставляет в заголовке кортежа бит-подсказку `HEAP_XMIN_FROZEN`. Версия считается замороженной, исходный `xid` остаётся виден для отладки. Делает заморозку [vacuum](/courses/postgres/kb/vacuum.md). ## relfrozenxid и age() У каждой таблицы есть `relfrozenxid` в `pg_class` - граница, ниже которой все версии заморожены. Полезнее смотреть её возраст: ```sql SELECT relname, age(relfrozenxid) AS xid_age FROM pg_class WHERE relkind = 'r' ORDER BY age(relfrozenxid) DESC LIMIT 10; ``` `age(relfrozenxid)` растёт с каждой транзакцией и падает после прохода VACUUM. На уровне базы то же показывает `datfrozenxid` в `pg_database` - минимум по всем таблицам. ## Пороги заморозки - `vacuum_freeze_min_age` (50 млн) - возраст версии, начиная с которого обычный VACUUM её морозит; - `autovacuum_freeze_max_age` (200 млн) - возраст таблицы, при котором запускается агрессивный анти-wraparound проход, даже если autovacuum выключен; - `vacuum_freeze_table_age` - возраст, при котором обычный VACUUM переходит в агрессивный режим (сканирует все страницы, а не только помеченные в карте видимости). Агрессивный проход отличается тем, что не доверяет карте видимости и проходит даже «всё видно всем» страницы - иначе заморозить версии в них было бы нельзя. ## Связь с multixact Параллельно с `relfrozenxid` существует `relminmxid` - граница заморозки multixact-идентификаторов (см. [multixact](/courses/postgres/kb/multixact.md)). VACUUM продвигает обе. ## Команды ```sql SELECT age(relfrozenxid) FROM pg_class WHERE relname = 'flights'; ``` Возраст таблицы в транзакциях — держать заметно ниже 200 млн ```sql VACUUM FREEZE flights; ``` Принудительно заморозить все пригодные версии и продвинуть relfrozenxid ```sql SELECT datname, age(datfrozenxid) FROM pg_database ORDER BY 2 DESC; ``` Возраст баз — какая ближе к опасной черте ## См. также - [Wraparound и колесо XID](/courses/postgres/kb/wraparound.md) - [Multixact и relminmxid](/courses/postgres/kb/multixact.md) - [VACUUM и removable cutoff](/courses/postgres/kb/vacuum.md) - [Autovacuum: пороги и bloat](/courses/postgres/kb/autovacuum.md)