Мы уже поняли, что
DELETE — операция тяжеловатая. Но внимательные могли заметить: я писал не «удаляет строку», а «помечает строку». И это важно.Давайте разберёмся, как
DELETE работает на самом деле.Когда PostgreSQL «удаляет» строку, он не вырезает её из таблицы. Он помечает её как неактуальную. Такая строка называется dead tuple — мёртвая версия строки.
Она:
- продолжает лежать в таблице
- занимает место на странице и на диске
- участвует в механизме чтения (они не возвращаются, так как отфильтровываются по visibility map, но увеличивают стоимость скана)
- не удаляется без VACUUM
То есть
DELETE — это не «убрали», а «оставили, но пометили как мусор».Почему так происходит
Причина — MVCC (многоверсионность).
PostgreSQL обязан:
- позволять другим транзакциям дочитать старые данные
- сохранять консистентность
- не блокировать чтение
Цена за это — версии строк. А при
DELETE появляется ещё и мёртвая версия, которая никуда не исчезает сразу.А проблема ли это вообще?
Пока dead tuples мало — нет.
Но при массовых операциях начинается цепная реакция.
- Вы удаляете строки, но место на диске не освобождается, а иногда даже продолжает расти.
- Чтение становится дороже: база проверяет видимость строк, даже если актуальных данных мало.
- VACUUM начинает работать дольше и чаще.
Самое неприятное
PostgreSQL не уменьшает размер таблицы автоматически.
Даже если VACUUM убрал большенство dead tuples — файл таблицы на диске останется прежнего размера.
Чтобы реально вернуть место, нужны тяжёлые меры:
- VACUUM FULL
- перенос данных
- партиционирование
А это уже операции, которые очень не хочется выполнять на живой системе под нагрузкой. А как жить в таком жестоком мире мы поговорим в следующем посте.
#devblogHowToDeleteInDatabase #tech