Postgresql vacuum

У PostgreSQL є так званий MVCC (Multiversion Concurrency Control), який забезпечує те, що кожна транзакція бачить свій зліпок даних, і транзакції читання даних ніколи не блокують транзакції записи даних. а також запис ніколи не блокує читання.

Для цього при виконанні SQL-команд UPDATE і DELETE фактичне видалення і зміна рядка ніколи не відбувається відразу. Насправді при виконанні UPDATE кожен раз створюється нова версія рядки, а й стара продовжує існувати. А при DELETE версія рядки тільки позначається, як віддалена конкретної транзакцією, але фактично не видаляється.

Зрештою, не залишається жодної живої транзакції, яка могла б побачити вміст рядка. В цьому випадку рядок можна видалити, а її місце позначити як доступне для використання при вставках рядків. Саме цим і займається VACUUM.

У команди VACUUM є два варіанти: звичайний і FULL.

Звичайний варіант тільки позначає рядки для майбутнього використання, але не повертає зайняте місце операційній системі крім крайніх випадків, коли одна або кілька сторінок в кінці простору таблиці виявляються повністю вільними:

Найчастіше використовується саме VACUUM. а VACUUM FULL можна викликати після якої-небудь процедури, яка дуже активно оновлювала дані. У PostgreSQL є стандартний демон, який періодично запускає саме операцію VACUUM. коли в цьому виникає потреба.

MVCC покладається на можливість порівняння ID (XID) версій транзакції, яка вставила рядок з XID поточної транзакції. Рядок, у якій XID транзакції, яка її вставила, більше XID поточної транзакції була вставлена ​​в майбутньому, а значить вона не повинна бути видна з поточної транзакції. Для ID транзакцій використовується 32 біта, тому при виконанні досить великої кількості транзакцій (більше чотирьох мільярдів) відбудеться так званий transaction ID wraparound. тобто ID Транзакції знову стане 0 і раптово все транзакції, які були в минулому виявляться в майбутньому, що призведе до того, що їх зміни стануть видимими.

Для того щоб уникнути transaction ID wraparound потрібно обов'язково виконувати VACUUM для кожної бази даних як мінімум раз в 2 мільярди транзакцій.

Яким же чином команда VACUUM виправляє проблему? У PostgreSQL є спеціальний XID транзакції FrozenXID. Цей XID не слід звичайними правилами порівняння ID і вважається завжди старше, ніж будь-яка нормальна XID. Звичайні XID порівнюються не як прості числа, а як циклічні. Для кожного XID є два мільярди XID-ів, які старше і два мільярди XID-ів, які новіше, тобто простір XID десятків замкнуто в кільце. Після створення рядка з яким-небудь звичайним XID рядок стає «в минулому» для двох мільярдів наступних транзакцій, незалежно від числа в їх XID. Якщо цей рядок до сих пір існує після двох мільярдів транзакцій, то вона випадково виявляється в майбутньому. Для того щоб запобігти цьому, попередніх його версій рядків в XID потрібно прописати FrozenXID до того, як ми досягнемо кордону в 2 мільярди транзакцій. Після присвоєння цього спеціального XID вони виявляться «в минулому» для всіх нормальних транзакцій, а тому вони будуть коректними аж до видалення, незалежно від того, через який час воно відбудеться. Присвоєння FrozenXID здійснює команда VACUUM. саме тому так важливо, щоб вона періодично виконувалася.

Ще записи з цієї рубрики:

Схожі статті