Как происходит удаление строк в PostgreSQL и почему место не освобождается сразу?

Ответ

В PostgreSQL удаление строк реализовано в рамках архитектуры MVCC (Multi-Version Concurrency Control), поэтому строки не удаляются физически сразу после выполнения команды DELETE.

Процесс удаления:

  1. Пометка строки: Вместо физического удаления, DELETE помечает строку как "мертвую" (dead tuple). Это делается путем записи ID транзакции, которая выполнила удаление, в системное поле строки xmax.
  2. Сохранение видимости: Старая версия строки остается видимой для транзакций, которые начались до момента фиксации удаления. Это обеспечивает изоляцию транзакций без блокировок на чтение.
  3. Очистка: Физическое удаление "мертвых" строк и освобождение места на диске происходит позже, во время процесса VACUUM.

Способы очистки:

  • VACUUM: Стандартная команда, которая находит "мертвые" строки и делает занимаемое ими место доступным для новых записей. Не блокирует таблицу для чтения и записи.
  • AUTOVACUUM: Фоновый процесс, который автоматически выполняет VACUUM для таблиц при достижении определенного порога измененных или удаленных строк.
  • VACUUM FULL: Перезаписывает всю таблицу в новый файл на диске, удаляя все "мертвые" строки и пустое пространство. Требует эксклюзивной блокировки таблицы на все время своей работы.
  • TRUNCATE TABLE: Быстро удаляет все строки из таблицы, не сканируя ее. Это DDL-операция, она немедленно освобождает место, но ее нельзя отменить, и она не запускает триггеры ON DELETE.
-- Помечает строку как удаленную, но место не освобождает
DELETE FROM users WHERE id = 42;

-- Физически очищает место от ранее удаленных строк
VACUUM users;

-- Быстро удаляет все строки и освобождает место
TRUNCATE TABLE users RESTART IDENTITY;

Ответ 18+ 🔞

Давай разберём эту хуйню про удаление в PostgreSQL, а то народ думает, что DELETE — это как в жизни: выкинул в мусорку и всё, пиздец. Ан нет, ёпта!

Представь себе, что у тебя в квартире бардак. Ты не выбрасываешь хлам, а просто пишешь на нём мелом «МУСОР» и ставишь дату. Вот так и работает DELETE. Он не стирает строку с диска, а просто помечает её как «мёртвую» — пишет в её служебное поле xmax номер своей транзакции. И всё. Строка лежит, как труп, и ждёт своего часа.

А зачем так сложно? А затем, чтобы другие транзакции, которые начали работать раньше, могли ещё видеть старые данные. Это называется MVCC — такая архитектура, которая позволяет читать без блокировок. Красота, блядь! Пока ты удалял, кто-то мог уже начать читать эту таблицу — и ему всё ещё видны старые строки. Волшебство, ёбана!

Но если так всё оставлять, то диск превратится в помойку из этих «мёртвых» строк. Тут на сцену выходит наш герой — процесс VACUUM.

  • Обычный VACUUM — это как уборщик, который ходит и выносит помеченный хлам. Он находит эти «мёртвые» строки и освобождает место под новые записи. Не блокирует таблицу, работает тихо, в фоне. Можно даже параллельно писать и читать.
  • AUTOVACUUM — это тот же уборщик, но на автоматике. Сам просыпается, когда намусорили достаточно, и подчищает. В идеале его всегда надо включать, чтобы не засирать базу до пизды.
  • VACUUM FULL — это уже капитальный ремонт с переездом. Он берёт всю таблицу, переписывает её заново в новый файл, выкидывая весь мусор и уплотняя всё, как следует. Но, сука, он требует эксклюзивной блокировки на всё время работы. Пока он трудится, к таблице не подступиться. Использовать осторожно, когда уже совсем овердохуища мусора.
  • TRUNCATE TABLE — это вообще термоядерный вариант. Он не помечает строки, он просто берёт и выкидывает всю таблицу в пизду. Место освобождается мгновенно, но это DDL-операция, её не откатить, и триггеры ON DELETE она не запускает. Резко и бесповоротно.
-- Помечаем строку как удалённую. Физически она ещё на диске.
DELETE FROM users WHERE id = 42;

-- Зовём уборщика, чтобы он вынес накопившийся мусор.
VACUUM users;

-- А это просто сносим всю хату к хуям собачьим.
TRUNCATE TABLE users RESTART IDENTITY;

Короче, запомни: DELETE — это просто пометка «убит». Чтобы реально почистить место, нужен VACUUM. А если надо всё и сразу — TRUNCATE, но с ним, как с гранатой: одно неверное движение, и прощай, данные. Чих-пых тебя в сраку!