Раздел 33 · PostgreSQL с нуля

VACUUM и autovacuum

junior~20 мин

без входаВойди, чтобы отмечать прогресс, вести заметки и решать задачи в редакторе. войти

В прошлом уроке журнал просмотров после двух обновлений вырос с 440 до 1304 kB при тех же 10 000 строк. В уроке 20 мы один раз запустили VACUUM и узнали, что есть фоновый autovacuum. Теперь разберём уборку по-настоящему: что VACUUM делает, чего не делает, и когда autovacuum приходит к таблице сам.

Уборка в кафе

В кафе после гостей остаются грязные столы. Официант протирает стол, и за него можно сажать новых гостей. Зал не становится меньше, но места снова свободны. Это обычная уборка.

Иногда кафе закрывают на день, сдвигают столы, выносят лишние и сдают освободившуюся часть зала в аренду. Места становится меньше, но гостей в этот день не обслуживают. Это генеральная перестановка.

У PostgreSQL две такие уборки: VACUUM и VACUUM FULL.

Что делает VACUUM

VACUUM проходит по таблице и делает три дела:

  1. Освобождает место. Мёртвые версии, которых не видит ни одна транзакция, вычищаются из страниц и из индексов. Освободившееся место попадает в карту свободного места, и новые версии строк лягут туда, а не в конец файла.
  2. Отмечает чистые страницы. Страницы, где все версии видны всем, попадают в карту видимости. По ней работает Index Only Scan из урока про стратегию индексирования, и по ней следующий VACUUM пропускает чистые страницы.
  3. Замораживает старые версии. Об этом ниже, в разделе про переполнение счётчика.

Главное, чего VACUUM не делает: он почти никогда не уменьшает файл таблицы. Место освобождается внутри файла. Проверим на журнале просмотров после одного обновления всех строк:

 table_size | relpages | reltuples | relallvisible
------------+----------+-----------+---------------
 872 kB     |        0 |        -1 |             0
(1 row)

Колонки из системного каталога pg_class: relpages и reltuples это число страниц и строк по последнему подсчёту, relallvisible число страниц в карте видимости. Пока VACUUM и ANALYZE не приходили, подсчёта нет: -1 значит «неизвестно». Запускаем уборку:

VACUUM views_log;
 table_size | relpages | reltuples | relallvisible
------------+----------+-----------+---------------
 872 kB     |      109 |     10000 |           109
(1 row)

Размер тот же, 872 kB. Зато все 109 страниц попали в карту видимости, а статистика обновилась. Теперь ещё раз обновим все строки:

UPDATE views_log SET hits = hits + 1;
 table_size
------------
 872 kB
(1 row)

Таблица не выросла. Новые версии легли на место, которое освободил VACUUM. Это и есть нормальный режим жизни таблицы: она один раз дорастает до размера «живые строки плюс запас под обновления» и дальше держится на нём.

VACUUM FULL

Если таблица уже раздута и запас не нужен, место можно вернуть системе:

VACUUM FULL views_log;
 table_size | relpages | relallvisible
------------+----------+---------------
 440 kB     |       55 |             0
(1 row)

Снова 440 kB, как сразу после вставки. VACUUM FULL переписал таблицу в новый файл только с живыми строками и перестроил индексы. Цена высокая: всё время работы таблица закрыта и для записи, и для чтения. На таблице в десятки гигабайт это минуты и часы простоя. Ещё он требует свободного места на диске под вторую копию. Заметь и relallvisible = 0: карту видимости после него заполнит уже обычный VACUUM.

Поэтому VACUUM FULL на рабочей базе запускают редко, в окно обслуживания, когда раздувание уже случилось. Задача обычного VACUUM в том, чтобы до этого не доводить.

урок из курса

Урок из курса «PostgreSQL с нуля». Курс покупается один раз и остаётся навсегда: 500 ₽.

Оплата пока не подключена: премиум и курсы открываются промокодом.