После массового удаления строк таблица не уменьшается сразу: как MVCC определяет момент безопасной очистки ...

После массового удаления строк таблица не уменьшается сразу: как MVCC определяет момент безопасной очистки старых версий?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

В MVCC удаление обычно не стирает строку физически, а создаёт признак или версию удаления. Старая версия должна сохраняться, пока существует транзакция, чей снимок ещё может её видеть. После этого фоновый процесс очистки удаляет устаревшие версии, но освобождённое место не обязательно сразу возвращается операционной системе.

Исторический контекст

MVCC появился как способ уменьшить конфликт между чтением и записью: читатели получают согласованный снимок, а писатели не обязаны блокировать их на всё время чтения. Цена такого подхода — необходимость хранить несколько версий одной строки и отдельно определять, когда старая версия больше никому не нужна.

Постановка проблемы

Если физически удалить старую версию сразу после операции удаления, длительная транзакция может потерять данные, которые должны быть доступны в её снимке. Поэтому логическое удаление и физическая очистка разделены.

Отложенная очистка приводит к росту таблицы и индексов, дополнительным затратам на сканирование устаревших версий и иногда к нехватке дискового пространства. При этом завершение операции удаления ещё не означает немедленного уменьшения размера файла таблицы.

Подробное решение

Транзакция, удаляющая строку, делает её невидимой для подходящих будущих снимков, но старая версия остаётся доступной транзакциям, начавшим чтение раньше. Аналогично при обновлении старая версия может быть нужна старому снимку, а новая — более поздним транзакциям.

СУБД отслеживает нижнюю границу активных снимков или эквивалентный ей показатель. Версию можно безопасно удалить, когда ни одна активная транзакция уже не способна её увидеть. Конкретный процесс называется по-разному: например, vacuum, очистка версий или purge — это зависит от СУБД.

Долгая транзакция, даже только читающая, может удерживать старые версии дольше обычного. Поэтому очистка будет отставать от удаления, а объём служебных данных — расти.

После очистки место часто помечается как свободное внутри таблицы и может быть переиспользовано последующими вставками. Возврат места операционной системе — отдельная операция, обычно более тяжёлая и способная требовать дополнительной перестройки; её необходимость и название зависят от конкретной СУБД.

Ситуация из практики

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

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

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

Что кандидаты часто упускают

  1. Почему удалённая строка может быть видна одной транзакции, но невидима другой?

    Это определяется снимком и границами видимости версий. Транзакция со старым снимком может видеть состояние до удаления, если удалившая транзакция на момент формирования снимка ещё не была видна. Более поздний снимок обычно уже не видит удалённую строку.

  2. Почему завершение длительной транзакции не всегда сразу уменьшает файл таблицы?

    Завершение транзакции лишь делает некоторые версии доступными для очистки. Фоновому процессу ещё нужно обнаружить их, удалить служебные записи и обработать индексы. Кроме того, очистка часто освобождает место для повторного использования внутри файла, но не обязана уменьшать его физический размер.

  3. Почему индексы тоже могут разрастаться при массовых обновлениях и удалениях?

    В MVCC устаревшие версии затрагивают не только основную таблицу, но и индексные структуры. Пока старые записи индекса потенциально нужны активным снимкам, их нельзя безопасно убрать. Поэтому очистка должна обрабатывать таблицу и индексы, а её отставание может ухудшать производительность поиска даже после завершения удаления.