Практика SQL
4 мин чтения·

Чем TRUNCATE отличается от DELETE и DROP

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

КритерийDELETETRUNCATEDROP
Что удаляетСтрокиВсе строкиТаблицу целиком
Условие WHEREДаНетНет
Скорость на большой таблицеМедленноМгновенноМгновенно
Триггеры ON DELETEСрабатываютНе срабатываютНе срабатывают
Сброс AUTO_INCREMENTНетMySQL — да, PostgreSQL — по запросуВместе с таблицей
Откат внутри транзакцииДаPostgreSQL — да, MySQL — нетPostgreSQL — да, MySQL — нет
Тип командыDMLDDLDDL

DELETE удаляет строки, 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.1
CREATE 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;
idmessage
4после DELETE

В таблице после DELETE FROM users вставили новую строку, и она получила id = 501, а не 1. Почему?

TRUNCATE: мгновенная очистка таблицы

MySQL 8.1
TRUNCATE TABLE logs;

TRUNCATE — команда уровня структуры (DDL). Вместо построчного удаления СУБД просто освобождает место, занятое таблицей, — как будто таблицу пересоздали заново. Поэтому TRUNCATE срабатывает за доли секунды и на миллионе строк, и на миллиарде.

За скорость приходится платить ограничениями:

  • Нет условия WHERE — только вся таблица сразу.
  • Триггеры ON DELETE не срабатывают: построчного удаления не происходит, и логика «при удалении строки сделай то-то» молча пропускается.
  • В MySQL TRUNCATE нельзя откатить. Как и любая DDL-команда, он неявно фиксирует текущую транзакцию. В PostgreSQL TRUNCATE транзакционный: внутри BEGIN ... ROLLBACK данные вернутся.

Счётчик автоинкремента в MySQL сбрасывается на единицу:

MySQL 8.1
TRUNCATE TABLE logs;
INSERT INTO logs (message) VALUES ('после TRUNCATE');

SELECT id, message FROM logs;
idmessage
1после TRUNCATE

В PostgreSQL по умолчанию последовательность продолжается — чтобы сбросить её, нужно явно попросить:

PostgreSQL 17.5
TRUNCATE TABLE logs RESTART IDENTITY;

DROP: удаление таблицы целиком

MySQL 8.1
DROP TABLE logs;

-- не упадёт с ошибкой, если таблицы уже нет
DROP TABLE IF EXISTS logs;

DROP уничтожает таблицу полностью: данные, структуру, индексы, триггеры, ограничения. После него вставить данные «обратно» некуда — таблицу придётся создавать заново через CREATE TABLE.

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

Подводный камень: внешние ключи

Если на таблицу ссылаются внешние ключи других таблиц, TRUNCATE откажется работать — даже когда ссылающиеся таблицы пусты. MySQL:

MySQL 8.1
TRUNCATE TABLE authors;
Ошибка
ERROR 1701 (42000): Cannot truncate a table referenced in a foreign key constraint

PostgreSQL даёт ту же ошибку, но сразу подсказывает решение:

MySQL 8.1
TRUNCATE TABLE authors;
Ошибка
ERROR: cannot truncate a table referenced in a foreign key constraint
DETAIL: Table "books" references "authors".
HINT: Truncate table "books" at the same time, or use TRUNCATE ... CASCADE.

В PostgreSQL можно очистить обе таблицы одной командой — TRUNCATE books, authors — или дописать CASCADE, который очистит и все ссылающиеся таблицы. С CASCADE будьте осторожны: он удалит данные из таблиц, о которых вы могли и не вспомнить.

DELETE в той же ситуации работает построчно и упадёт, только если на конкретную удаляемую строку есть ссылки.

Что выбрать: три типовых сценария

  • Удалить часть данных по условию — только DELETE. Он же — если нужны триггеры или возможность отката в MySQL.
  • Полностью очистить таблицу под новую загрузку данныхTRUNCATE: быстро, место освобождается сразу, счётчик можно сбросить. Типичный случай — таблицы логов, стейджинговые таблицы перед перезаливкой.
  • Избавиться от таблицы навсегдаDROP.

Таблица статистики на 200 миллионов строк перезаливается каждую ночь целиком. Какой командой лучше очищать её перед загрузкой?

Вопрос с собеседования

«Можно ли откатить TRUNCATE?» — любимый вопрос-ловушка. Правильный ответ зависит от СУБД: в PostgreSQL — да, TRUNCATE подчиняется транзакциям, и ROLLBACK вернёт данные. В MySQL и Oracle — нет: TRUNCATE неявно фиксирует транзакцию, и вернуть данные можно только из резервной копии. Ответ «нет, никогда» или «да, всегда» — повод для уточняющих вопросов интервьюера.

Что дальше

Читайте по теме