(раздувание) накопление неиспользуемого пространства (занятого старыми версиями строк) в таблицах и индексах PostgreSQL

При операциях UPDATE или DELETE благодаря использованию MVCC система не удаляет устаревшие данные сразу, а помечает их как неактивные, создавая (при UPDATE) новые версии строк. Со временем количество помеченных строк растёт — они занимают место на диске, хотя уже не используются. Последствия Bloat:

  • Увеличивается потребление дискового пространства (реальный объём данных может быть в разы меньше занимаемого места)
  • Снижается производительность запросов (увеличивается объём сканируемых данных)
  • Растут размер и время создания резервных копий
Как обнаружить Bloat:

SELECT schemaname,
    tablename,
    round(100 * (n_dead_tup / (n_live_tup + n_dead_tup)::float)) AS dead_tup_percent, -- это приблизительная оценка неактивных строк
    n_live_tup,
    n_dead_tup
FROM pg_stat_user_tables
WHERE n_live_tup > 0 AND n_dead_tup > 0
ORDER BY dead_tup_percent DESC;

--Индексы тоже можно проверить, но для этого потребуется отдельное расширение
CREATE EXTENSION IF NOT EXISTS pgstattuple;
SELECT * FROM pgstatindex('index_name'); -- leaf_fragmentation выше 50 % может указывать на bloat, но не всегда.

Освободить неиспользуемое пространство можно с помощью VACUUM.