Питання на співбесіді: Експлуатація БД
Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.
16 питань
DELETE FROM events WHERE created_at < '2025-01-01' на 50 мільйонах рядків в одній транзакції:
- тримає блокування рядків годинами;
- генерує величезний обсяг WAL - репліки відстають, диск з архівом WAL заповнюється;
- утримує горизонт вакууму для всієї бази, поки триває;
- при скасуванні чи збої відкочується так само довго;
- після завершення лишає 50 мільйонів мертвих рядків, які вакууму ще прибирати.
Правильно - порціями:
-- повторювати, доки видаляється хоч щось
DELETE FROM events
WHERE id IN (
SELECT id FROM events
WHERE created_at < '2025-01-01'
ORDER BY id
LIMIT 10000
);
Кожна порція - коротка транзакція. Між порціями - невелика пауза, щоб вакуум і репліки встигали. У Laravel - команда з циклом і ->limit(10000)->delete() чи chunkById з видаленням.
Що контролювати під час видалення: затримку реплікації, кількість мертвих рядків, навантаження на диск. Зупиняти й продовжувати безпечно - кожна порція вже завершена.
Ще краще - не видаляти рядки взагалі. Якщо дані регулярно видаляються за віком (логи, події, метрики), таблицю варто партиціонувати за часом. Тоді видалення старого місяця - це:
ALTER TABLE events DETACH PARTITION events_2024_12;
DROP TABLE events_2024_12;
Миттєво, без мертвих рядків, без навантаження на вакуум і без величезного WAL.
Якщо треба видалити більшість таблиці (залишити 5%), швидше скопіювати потрібні рядки в нову таблицю, перейменувати й видалити стару - але це потребує вікна обслуговування й уваги до зовнішніх ключів і прав.
Після масового видалення: VACUUM (звичайний) звільнить місце для повторного використання, але файл таблиці не зменшиться. Повернути місце ОС без довгого ексклюзивного блокування допоможе pg_repack; VACUUM FULL блокує таблицю на весь час роботи.