Чем TRUNCATE отличается от DELETE и DROP
Короткий ответ: DELETE удаляет строки (все или по условию WHERE), TRUNCATE мгновенно очищает таблицу целиком, DROP удаляет саму таблицу вместе со структурой и данными. Полная картина различий — в таблице:

Теперь разберём каждую команду и нюансы, которые любят спрашивать на собеседованиях.
DELETE: удаление строк по условию
DELETE — единственная команда из трёх, которая умеет удалять выборочно:
MySQL 8.1-- удалить отменённые заказы старше года DELETE FROM orders WHERE status = 'canceled' AND order_date < '2025-06-12'; -- удалить все строки (таблица останется) DELETE FROM orders;
DELETE — команда уровня данных (DML). СУБД обрабатывает строки по одной: проверяет условие, пишет каждую удалённую строку в журнал, запускает триггеры ON DELETE. Отсюда два следствия:
- Удаление можно откатить. Пока транзакция не зафиксирована, ROLLBACK вернёт все строки на место.
- На больших таблицах это медленно. Удаление десяти миллионов строк может занять минуты и раздуть журнал транзакций.
Счётчик автоинкремента DELETE не трогает. Если удалить все строки и вставить новую, нумерация продолжится с того места, где остановилась:
MySQL 8.1CREATE TABLE logs ( id INT AUTO_INCREMENT PRIMARY KEY, message VARCHAR(100) ); INSERT INTO logs (message) VALUES ('первая'), ('вторая'), ('третья'); DELETE FROM logs; INSERT INTO logs (message) VALUES ('после DELETE'); SELECT id, message FROM logs;
В таблице после DELETE FROM users вставили новую строку, и она получила id = 501, а не 1. Почему?
TRUNCATE: мгновенная очистка таблицы
MySQL 8.1TRUNCATE TABLE logs;
TRUNCATE — команда уровня структуры (DDL). Вместо построчного удаления СУБД просто освобождает место, занятое таблицей, — как будто таблицу пересоздали заново. Поэтому TRUNCATE срабатывает за доли секунды и на миллионе строк, и на миллиарде.
За скорость приходится платить ограничениями:
- Нет условия WHERE — только вся таблица сразу.
- Триггеры ON DELETE не срабатывают: построчного удаления не происходит, и логика «при удалении строки сделай то-то» молча пропускается.
- В MySQL TRUNCATE нельзя откатить. Как и любая DDL-команда, он неявно фиксирует текущую транзакцию. В PostgreSQL TRUNCATE транзакционный: внутри BEGIN ... ROLLBACK данные вернутся.
Счётчик автоинкремента в MySQL сбрасывается на единицу:
MySQL 8.1TRUNCATE TABLE logs; INSERT INTO logs (message) VALUES ('после TRUNCATE'); SELECT id, message FROM logs;
В PostgreSQL по умолчанию последовательность продолжается — чтобы сбросить её, нужно явно попросить:
PostgreSQL 17.5TRUNCATE TABLE logs RESTART IDENTITY;
DROP: удаление таблицы целиком
MySQL 8.1DROP TABLE logs; -- не упадёт с ошибкой, если таблицы уже нет DROP TABLE IF EXISTS logs;
DROP уничтожает таблицу полностью: данные, структуру, индексы, триггеры, ограничения. После него вставить данные «обратно» некуда — таблицу придётся создавать заново через CREATE TABLE.
DROP нужен, когда таблица больше не нужна в принципе: временные таблицы, устаревшие части схемы, артефакты экспериментов. Если цель — просто избавиться от данных, DROP — перебор: вместе с данными исчезнут права, индексы и всё, что на таблицу ссылалось.
Подводный камень: внешние ключи
Если на таблицу ссылаются внешние ключи других таблиц, TRUNCATE откажется работать — даже когда ссылающиеся таблицы пусты. MySQL:
MySQL 8.1TRUNCATE TABLE authors;
PostgreSQL даёт ту же ошибку, но сразу подсказывает решение:
MySQL 8.1TRUNCATE TABLE authors;
В PostgreSQL можно очистить обе таблицы одной командой — TRUNCATE books, authors — или дописать CASCADE, который очистит и все ссылающиеся таблицы. С CASCADE будьте осторожны: он удалит данные из таблиц, о которых вы могли и не вспомнить.
DELETE в той же ситуации работает построчно и упадёт, только если на конкретную удаляемую строку есть ссылки.
Что выбрать: три типовых сценария
- Удалить часть данных по условию — только DELETE. Он же — если нужны триггеры или возможность отката в MySQL.
- Полностью очистить таблицу под новую загрузку данных — TRUNCATE: быстро, место освобождается сразу, счётчик можно сбросить. Типичный случай — таблицы логов, стейджинговые таблицы перед перезаливкой.
- Избавиться от таблицы навсегда — DROP.
Таблица статистики на 200 миллионов строк перезаливается каждую ночь целиком. Какой командой лучше очищать её перед загрузкой?
Вопрос с собеседования
«Можно ли откатить TRUNCATE?» — любимый вопрос-ловушка. Правильный ответ зависит от СУБД: в PostgreSQL — да, TRUNCATE подчиняется транзакциям, и ROLLBACK вернёт данные. В MySQL и Oracle — нет: TRUNCATE неявно фиксирует транзакцию, и вернуть данные можно только из резервной копии. Ответ «нет, никогда» или «да, всегда» — повод для уточняющих вопросов интервьюера.
Что дальше
- синтаксис и тонкости DELETE — в уроке Удаление данных, оператор DELETE;
- почему DDL-команды в MySQL нельзя откатить — в уроке Транзакции;
- закрепить разницу на практике — в тренажёре SQL.
Читайте по теме
ROW_NUMBER, RANK и DENSE_RANK в SQL: отличия на одном примере
Три ранжирующие функции, один запрос — и разница видна
COALESCE в SQL: что это и как работает — примеры | SQL Academy
Первый не-NULL аргумент, и зачем рядом NULLIF
CTE в SQL: что такое Common Table Expression (WITH) — примеры
Подзапросы с именами, цепочки шагов и рекурсия