Но остаётся главный вопрос:
а как вообще выносят мусор?
Ведь строки остаются.
И если их не убирать — таблица рано или поздно превратится в свалку.
На первый взгляд всё кажется простым.
Ну правда, что может пойти не так?
DELETE FROM messages
WHERE deleted_at < now() - interval '30 days';
Но как бы мило и аккуратно ни выглядел этот запрос,
на больших объёмах он может сделать очень больно:
- огромный DELETE → всплеск WAL
- долгий и тяжёлый ближайший VACUUM
- просадки по latency
- неожиданные тормоза в живом трафике.
Если у вас ночью почти нет нагрузки — да, такой вариант иногда можно себе позволить.
Но что делать, если у вас постоянный поток операций и «тихого времени» просто не существует?
Постепенный вынос мусора
В этом случае мусор выносят маленькими порциями.
Типичный подход выглядит так:
- раз в 5 минут
- удаляем 1–5 тысяч строк
- без спешки
- без пиков нагрузки
Пример запроса:
DELETE FROM messages
WHERE id IN (
SELECT id
FROM messages
WHERE deleted_at < now() - interval '30 days'
ORDER BY deleted_at
LIMIT 5000
);
Что это даёт:
- Ограниченный WAL — без резких всплесков.
- Короткие транзакции — меньше блокировок.
- Предсказуемую нагрузку — без сюрпризов для продакшена.
- Возможность спокойно жить даже под постоянным трафиком.
И главное, что стоит запомнить
Soft delete — это не “никогда не удалять”.
Это “удалять тогда, когда системе удобно”.
Он не является панацеей от всех проблем,
но его разумное использование может сократить их.
#devblogHowToDeleteInDatabase #tech