DELETE, TRUNCATE и DROP: как удалить данные в SQL

DELETE, TRUNCATE и DROP: как удалить данные в SQL Полезное

Удаление данных в SQL — это операция, которая стирает строки таблицы или саму таблицу целиком, и ведет себя по-разному в зависимости от выбранного оператора. DELETE убирает строки по условию и пишет каждую строку в журнал транзакций, TRUNCATE разом очищает всю таблицу, а DROP убирает и данные, и саму структуру таблицы. Дальше разберем синтаксис каждого варианта, откат через транзакцию и отличия MySQL, PostgreSQL и SQL Server.

Три оператора удаления: короткий словарь

Прежде чем сравнивать команды, разведем термины, которые часто путают:

  • DELETE — DML-команда, удаляет отдельные строки таблицы по условию WHERE, структура таблицы остается.
  • TRUNCATE — быстро очищает всю таблицу целиком, WHERE не поддерживает, структура таблицы остается.
  • DROP — удаляет саму таблицу: и данные, и структуру, и связанные индексы.

Дальше по каждому — синтаксис и пример.

DELETE: удаление строк по условию

DELETE стирает строки, которые подходят под условие WHERE. Без WHERE удалятся все строки таблицы — это частая ошибка, разберем ее отдельно ниже.

Полный синтаксис:

DELETE FROM таблица
WHERE условие;

Рабочий пример на маленькой таблице:

CREATE TABLE students (
    id INT PRIMARY KEY,
    name VARCHAR(100),
    course VARCHAR(50),
    status VARCHAR(20)
);

INSERT INTO students (id, name, course, status) VALUES
    (1, 'Иванов', 'SQL', 'active'),
    (2, 'Петров', 'SQL', 'dropped'),
    (3, 'Сидорова', 'Python', 'active');

DELETE FROM students WHERE status = 'dropped';

Результат: удалится одна строка (Петров, id 2), останутся Иванов и Сидорова. Если запустить SELECT * FROM students; после этого, увидим только две строки, а id 2 не появится снова — DELETE не переиспользует и не сбрасывает счетчики id.

WHERE в примере отбирает строки по значению столбца status. Условие может использовать любые операторы сравнения, IN, подзапросы — логика та же, что и в SELECT. DELETE активирует триггеры уровня строки, если они определены на таблице (например, лог удалений в отдельную таблицу).

TRUNCATE: быстрая очистка всей таблицы

TRUNCATE не принимает условие отбора — он всегда стирает все строки таблицы сразу. За счет минимального логирования (без построчной записи в журнал транзакций) TRUNCATE заметно быстрее DELETE на больших таблицах.

TRUNCATE TABLE students;

После этой команды таблица students пустая, но сама таблица, ее столбцы и индексы остаются — можно сразу вставлять новые строки. TRUNCATE, как правило, не активирует построчные DELETE-триггеры (это отличает его от DELETE без условия, который такие триггеры вызывает).

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

DROP убирает не только строки, но и саму таблицу — структуру, индексы, ограничения и права на объект.

DROP TABLE students;

После DROP обращение SELECT * FROM students; вернет ошибку — таблицы больше не существует. Чтобы работать с данными снова, таблицу нужно создавать заново командой CREATE TABLE и заполнять данными из бэкапа.

DELETE vs TRUNCATE vs DROP: сравнение

Критерий DELETE TRUNCATE DROP
Что удаляет строки по условию все строки сразу таблицу целиком: строки + структура
Условие WHERE да нет нет
Построчные триггеры вызывает как правило нет не применимо (таблицы нет)
Счетчик id / identity не трогает сбрасывает (детали по СУБД ниже) таблицы нет, счетчик исчезает вместе с ней
Тип операции DML DDL (в части СУБД) DDL
Скорость на больших таблицах медленнее быстрее DELETE быстрая, но необратимая по структуре

Диалектные отличия: MySQL, PostgreSQL, MS SQL

Поведение TRUNCATE и DROP внутри транзакции зависит от конкретной СУБД — это частая причина неожиданностей.

В MySQL (InnoDB) TRUNCATE TABLE и DROP TABLE выполняют неявный commit: если запустить их внутри транзакции и потом дать ROLLBACK, откатить их не получится, откатится только то, что было до них.

В PostgreSQL DDL транзакционен: TRUNCATE и DROP TABLE, выполненные внутри явной транзакции (BEGIN … ROLLBACK), можно откатить полностью, как обычные DML-команды.

В MS SQL Server TRUNCATE TABLE и DROP TABLE тоже можно откатить, если они выполнены внутри явной транзакции BEGIN TRAN … ROLLBACK — в этом MS SQL ближе к PostgreSQL, чем к MySQL.

Сброс счетчика identity после TRUNCATE тоже отличается по диалектам. В MySQL AUTO_INCREMENT сбрасывается к начальному значению автоматически. В SQL Server IDENTITY сбрасывается к заданному seed автоматически. В PostgreSQL обычный TRUNCATE счетчик последовательности НЕ сбрасывает — для сброса нужно явно указать TRUNCATE TABLE students RESTART IDENTITY;.

Безопасное удаление: WHERE, транзакция, бэкап

DELETE без WHERE — самая частая и самая дорогая ошибка при работе с SQL. Команда ниже удалит абсолютно все строки таблицы без единого предупреждения от СУБД:

DELETE FROM students;

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

Первый шаг — посмотреть, что попадет под удаление, обычным SELECT с тем же условием:

SELECT * FROM students WHERE status = 'dropped';

Второй шаг — сделать резервную копию затрагиваемых данных (пример для MySQL/PostgreSQL, синтаксис создания таблицы из выборки):

CREATE TABLE students_backup_20260919 AS
SELECT * FROM students WHERE status = 'dropped';

Третий шаг — выполнить само удаление внутри явной транзакции, чтобы иметь возможность откатить результат до commit:

BEGIN;
DELETE FROM students WHERE status = 'dropped';
-- здесь проверяем результат: SELECT count(*) FROM students;
COMMIT;
-- если результат неверный - ROLLBACK; вместо COMMIT отменит удаление

Для MySQL и SQL Server команда начала транзакции пишется как START TRANSACTION; и BEGIN TRAN; соответственно, а логика та же: удаление подтверждается COMMIT только после проверки. Для TRUNCATE и DROP этот способ отката работает не во всех СУБД — см. раздел про диалекты выше: в MySQL транзакция их не спасет из-за неявного commit.

Выводы

  • DELETE удаляет строки по условию WHERE, пишет их в журнал транзакций и не трогает счетчик id.
  • TRUNCATE быстро очищает всю таблицу целиком, WHERE не поддерживает, обычно не вызывает построчные триггеры.
  • DROP удаляет саму таблицу — данные и структуру — и требует пересоздания таблицы для восстановления работы.
  • В MySQL TRUNCATE и DROP делают неявный commit и не откатываются, в PostgreSQL и SQL Server их можно откатить внутри явной транзакции.
  • Перед удалением на живой базе: SELECT-предпросмотр, бэкап затронутых строк, затем DELETE внутри транзакции с проверкой перед COMMIT.

Где применяется / связь с практикой

Разница между DELETE, TRUNCATE и DROP регулярно всплывает на практике: очистка тестовых данных перед перезаливкой, удаление неактуальных записей по условию, полный снос временной таблицы после ETL-процесса. Ошибка в выборе оператора здесь стоит дорого — можно как потерять нужные строки, так и оставить мусор в проде.

Освойте тему на практике

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

Освойте тему на практике

Проверить формат перед записью на курс можно на открытых уроках Otus — там показывают разбор похожих практических задач вживую.

FAQ

Можно ли восстановить строки после DELETE, если бэкапа нет?
Если транзакция еще не подтверждена COMMIT, поможет ROLLBACK. После commit восстановление возможно только средствами администратора БД — через point-in-time recovery по журналу транзакций, если он настроен и хранится за нужный период; штатных пользовательских средств для этого нет.

Что быстрее на таблице с миллионами строк — DELETE или TRUNCATE?
TRUNCATE быстрее, потому что не пишет в журнал транзакций удаление каждой отдельной строки. Если нужно удалить действительно все строки без условия, TRUNCATE предпочтительнее DELETE без WHERE.

Как удалить строки сразу из нескольких связанных таблиц по одному условию?
Синтаксис отличается по диалектам: в MySQL это DELETE с несколькими именами таблиц перед FROM и JOIN в условии, в PostgreSQL — DELETE … USING, в SQL Server — DELETE … FROM с JOIN. Это отдельная тема продвинутого синтаксиса, требует аккуратной проверки условий join перед запуском на реальных данных.

OTUS Журнал
Бесплатные открытые уроки (поп-ап)