TRUNCATE и DELETE в SQL: чем отличаются и как очистить таблицу

TRUNCATE TABLE удаляет все строки таблицы одной командой и оставляет её структуру.

Разбираем, чем он отличается от DELETE: что можно откатить, когда сбрасывается id и почему мешают внешние ключи.

Внутри примеры с выводом для PostgreSQL и MySQL и замер скорости на миллионе строк.

Статью написал:
Ваня Буявец, продюсер, основатель Checkroi
Ваня Буявец
Основатель Checkroi, продюсер, эксперт в выборе онлайн-курсов
Все 3139 статей автора Подписаться на Телеграм-канал
Одобрено экспертом:
Наташа Буявец, основатель Checkroi, эксперт по онлайн-курсам
Наташа Буявец
Основательница Checkroi, продюсер Youtube-каналов, эксперт по онлайн-курсам
Все 3793 экспертных мнения Подписаться на Телеграм-канал
Обложка: TRUNCATE и DELETE в SQL: чем отличаются и как очистить таблицу

TRUNCATE в SQL очищает таблицу целиком одной командой: TRUNCATE TABLE orders; Строки исчезают, а сама таблица, её столбцы, индексы и права остаются на месте. DELETE делает похожую работу иначе: удаляет строки по условию WHERE, проходит по ним по одной и вызывает триггеры.

Если нужно удалить часть записей, берите DELETE. Если нужна пустая таблица и никто, кроме вас, с ней сейчас не работает, быстрее TRUNCATE. Ниже синтаксис для пяти СУБД, сравнение по восьми пунктам и замер скорости на миллионе строк. Если вы только начинаете с запросами, сначала прочитайте что такое язык SQL.

CheckroiCheckroiПодборка курсов по SQL422 курса • 40 школСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить→

Синтаксис TRUNCATE в PostgreSQL, MySQL, SQL Server и Oracle

Рой очищает таблицу базы данных одной командой

Базовая форма одинакова почти везде:

TRUNCATE TABLE имя_таблицы;

Отличаются дополнительные параметры и одна СУБД, где команды нет вовсе.

СУБД Как очистить таблицу Особенность
PostgreSQL TRUNCATE orders RESTART IDENTITY CASCADE; слово TABLE можно опустить, можно очистить несколько таблиц через запятую
MySQL TRUNCATE TABLE orders; нужно право DROP, команда сразу фиксирует транзакцию
SQL Server TRUNCATE TABLE orders; можно очистить отдельные секции: WITH (PARTITIONS (2, 4))
Oracle TRUNCATE TABLE orders; откатить нельзя, есть CASCADE для дочерних таблиц с ON DELETE CASCADE
SQLite DELETE FROM orders; TRUNCATE нет, DELETE без WHERE и без триггеров СУБД сама выполняет как быструю очистку

В SQLite запрос TRUNCATE TABLE orders; падает с ошибкой near "TRUNCATE": syntax error. Быстрый режим для DELETE без условия описан в разделе The Truncate Optimization документации SQLite.

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

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

Обе команды могут оставить таблицу пустой, но устроены по-разному. DELETE работает со строками, а TRUNCATE со всей таблицей сразу. Отсюда все остальные различия.

Что сравниваем DELETE TRUNCATE
Условие WHERE есть нет, удаляются все строки
Триггеры ON DELETE срабатывают на каждую строку не срабатывают
Счётчик id не сбрасывается MySQL и SQL Server сбрасывают, PostgreSQL только с RESTART IDENTITY
Откат через ROLLBACK везде PostgreSQL и SQL Server да, MySQL и Oracle нет
Таблица, на которую ссылается внешний ключ можно, если нет ссылающихся строк ошибка, даже если дочерняя таблица пуста
Сколько строк удалено СУБД сообщает точное число MySQL пишет «0 rows affected»
Блокировка в PostgreSQL чтению не мешает ACCESS EXCLUSIVE на всю таблицу
Право в MySQL DELETE DROP

Про триггеры, блокировку и внешние ключи в PostgreSQL написано в разделе «Примечания» описания команды TRUNCATE. Для MySQL то же самое собрано в справке TRUNCATE TABLE: там прямо сказано, что «0 rows affected» значит «нет информации», а не ноль удалённых строк. Точное число строк до очистки удобно узнать функцией COUNT.

Канал основателя Checkroi Вани Буявца3 700 человек читают мой Телеграм-канал про нейросетиСобрал промпты для Claude Code и ChatGPT, разборы ИИ-инструментов и лайфхаки по продвижению бизнеса в одном местеПрисоединиться

Что быстрее: замер на миллионе строк

Два способа очистить таблицу: построчно и целиком

Мы заполнили две одинаковые таблицы миллионом строк (числовой ключ и короткий текст), одну очистили через DELETE без условия, другую через TRUNCATE. Каждую пару запускали трижды на обычном ноутбуке.

СУБД DELETE FROM big TRUNCATE TABLE big2
PostgreSQL 17 от 0,27 до 2,7 секунды от 3 до 11 миллисекунд
MySQL (InnoDB) от 1,39 до 1,49 секунды 8–9 миллисекунд

Разница в десятки и сотни раз появляется потому, что DELETE проходит по каждой строке и записывает её удаление в журнал, а TRUNCATE просто освобождает место, занятое таблицей. Чем больше строк и индексов, тем заметнее разрыв. На таблице из сотни записей вы его не увидите.

У PostgreSQL время DELETE заметно менялось от прогона к прогону, а у TRUNCATE почти нет.

Сбрасывает ли TRUNCATE счётчик id

Зависит от СУБД, и здесь легче всего ошибиться.

PostgreSQL: по умолчанию не сбрасывает

CREATE TABLE orders (
  id      serial PRIMARY KEY,
  client  text,
  status  text
);
INSERT INTO orders (client, status) VALUES
  ('Анна', 'paid'), ('Борис', 'cancelled'), ('Вера', 'paid');

TRUNCATE TABLE orders;
INSERT INTO orders (client, status) VALUES ('Глеб', 'paid');
SELECT * FROM orders;
 id | client | status
----+--------+--------
  4 | Глеб   | paid

TRUNCATE TABLE orders RESTART IDENTITY;
INSERT INTO orders (client, status) VALUES ('Дина', 'paid');
SELECT * FROM orders;
 id | client | status
----+--------+--------
  1 | Дина   | paid

Без параметра действует CONTINUE IDENTITY. Документация PostgreSQL называет его поведением по умолчанию: последовательность не меняется, и новые строки продолжают нумерацию. Как устроены serial, IDENTITY и последовательности, разбирают на курсах по PostgreSQL.

MySQL и SQL Server: сбрасывают

В MySQL после TRUNCATE AUTO_INCREMENT возвращается к началу, а после DELETE нет:

DELETE FROM orders;
INSERT INTO orders (client, status) VALUES ('Глеб', 'paid');
SELECT * FROM orders;
+----+--------+--------+
| id | client | status |
+----+--------+--------+
|  4 | Глеб   | paid   |
+----+--------+--------+

TRUNCATE TABLE orders;
INSERT INTO orders (client, status) VALUES ('Дина', 'paid');
SELECT * FROM orders;
+----+--------+--------+
| id | client | status |
+----+--------+--------+
|  1 | Дина   | paid   |
+----+--------+--------+

SQL Server ведёт себя так же. По справке Microsoft, счётчик столбца IDENTITY возвращается к начальному значению, а если оно не задано, к единице. Чтобы сохранить нумерацию, Microsoft советует DELETE.

Можно ли откатить TRUNCATE

Рой радуется, что откат вернул данные в таблицу

В PostgreSQL можно. Очистка внутри транзакции отменяется так же, как обычный DELETE:

BEGIN;
TRUNCATE TABLE orders;
SELECT count(*) FROM orders;
 count
-------
     0

ROLLBACK;
SELECT count(*) FROM orders;
 count
-------
     3

В MySQL тот же сценарий не работает. TRUNCATE вызывает неявный COMMIT, поэтому после ROLLBACK таблица остаётся пустой:

START TRANSACTION;
TRUNCATE TABLE orders;
ROLLBACK;
SELECT count(*) FROM orders;
+----------+
| count(*) |
+----------+
|        0 |
+----------+
  • SQL Server откатывает TRUNCATE внутри транзакции, в справке Microsoft это пример C «Откат операции усечения».
  • Oracle не откатывает и не даёт вернуть данные через FLASHBACK TABLE, об этом сказано в документации Oracle.

Если вы не уверены, в какой СУБД работаете, считайте TRUNCATE необратимым и делайте копию таблицы заранее. Версию сервера видно в свойствах подключения любого клиента, например DBeaver.

TRUNCATE и внешние ключи

Добавим таблицу позиций заказа, которая ссылается на orders. Даже когда в ней нет ни одной строки, PostgreSQL откажется чистить родительскую таблицу:

TRUNCATE TABLE orders;
ERROR:  cannot truncate a table referenced in a foreign key constraint
DETAIL:  Table "items" references "orders".
HINT:  Truncate table "items" at the same time, or use TRUNCATE ... CASCADE.

Решение: перечислить обе таблицы в одной команде (TRUNCATE orders, items;) или добавить CASCADE. Второй вариант очистит все таблицы, которые ссылаются на orders, поэтому сначала проверьте, какие это таблицы.

MySQL возвращает ошибку 1701:

ERROR 1701 (42000): Cannot truncate a table referenced in a foreign key constraint (`shop`.`items`, CONSTRAINT `items_ibfk_1`)

CASCADE в MySQL нет. Остаётся DELETE, который пройдёт, если ссылающихся строк нет, или очистка с выключенной проверкой ключей: SET FOREIGN_KEY_CHECKS = 0; перед TRUNCATE и SET FOREIGN_KEY_CHECKS = 1; после. Тогда за целостность связей отвечаете вы: строки в items останутся ссылаться на несуществующие заказы. SQL Server тоже не даёт очищать таблицу, на которую ссылается FOREIGN KEY. Как таблицы связываются между собой, разобрано в статье про JOIN в SQL.

Ваня БуявецКанал основателя Checkroi Вани БуявцаЗабирайте промпты и обучение по нейросетям в моём Телеграм-каналеБольше 3 700 человек уже применяют Claude Code, ChatGPT и другие нейросети в работе, учёбе, бизнесе и жизниПерейти в канал

DELETE, TRUNCATE или DROP: что выбрать

  • Удалить часть строк, например отменённые заказы или записи старше года. Здесь подходит только DELETE с WHERE.
  • Очистить таблицу перед новой загрузкой: тестовые данные, промежуточную таблицу для выгрузки. Берите TRUNCATE.
  • Очистить таблицу с триггерами аудита. Нужен DELETE, иначе журнал удалений останется пустым.
  • Убрать таблицу совсем вместе со структурой поможет DROP TABLE. После него запрос к таблице вернёт ошибку, её придётся создавать заново.

Частые ошибки

DELETE без WHERE на рабочей базе

Запрос DELETE FROM orders; синтаксически верен, и СУБД выполнит его без предупреждения.

Решение: сначала запустите SELECT с тем же условием и посмотрите, что попадёт под удаление. Потом выполните DELETE внутри транзакции и подтвердите COMMIT, только если число удалённых строк совпало.

TRUNCATE на таблице, с которой работают другие

В PostgreSQL TRUNCATE берёт блокировку ACCESS EXCLUSIVE. Пока блокировка не снята, к таблице не пройдёт даже чтение, а сама команда будет ждать завершения чужих запросов.

Решение: чистить такие таблицы, когда нагрузка минимальна, например ночью, или удалять строки через DELETE порциями.

Ожидание, что id начнутся с единицы

В PostgreSQL после обычного TRUNCATE нумерация продолжится с последнего значения. Если код или тесты рассчитывают на id = 1, добавьте RESTART IDENTITY.

Проверка по числу удалённых строк в MySQL

Скрипт, который проверяет результат по «rows affected», после TRUNCATE увидит 0 и решит, что ничего не удалилось. Проверяйте результат запросом SELECT count(*).

Где освоить SQL системно

Разница между TRUNCATE и DELETE упирается в транзакции, блокировки и внешние ключи. Эти темы, а ещё оптимизацию запросов, подробно разбирают на курсах SQL. Подборка ниже собрана из каталога Checkroi, а если вы думаете о профессии, начните с плана, как стать SQL-разработчиком.

КурсШколаСтоимость со скидкойВ рассрочкуДлитель­ностьОбзор курса от Checkroi
Нейросети для рабочих задач
Перейти на сайт курса
SkillboxSkillbox31 290 ₽ - 1 месяцОбзор курса
SQL для анализа данных
Перейти на сайт курса
SkillboxSkillbox52 353 ₽6203 ₽/мес.2 месяцаОбзор курса
SQL-разработчик: тариф PRO
Перейти на сайт курса
Академия ЭдюсонЭдюсон89 900 ₽7491 ₽/мес.2 месяцаОбзор курса
SQL-разработчик: тариф Базовый
Перейти на сайт курса
Академия ЭдюсонЭдюсон79 900 ₽3329 ₽/мес.3 месяцаОбзор курса
SQL с нуляSkyproSkypro134 640 ₽5500 ₽/мес.12 месяцевОбзор курса

Больше программ — в полном каталоге курсов по SQL

Часто задаваемые вопросы

Что делает TRUNCATE в SQL?

Удаляет все строки таблицы одной командой и оставляет саму таблицу: столбцы, индексы, ограничения и права. Условия WHERE у команды нет, поэтому удалить часть строк через неё нельзя.

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

DELETE удаляет строки по условию, проходит по ним по одной, вызывает триггеры ON DELETE и всегда откатывается в транзакции. TRUNCATE очищает таблицу целиком, триггеры ON DELETE не вызывает, а откатить его можно только в PostgreSQL и SQL Server.

Что быстрее, TRUNCATE или DELETE?

На больших таблицах TRUNCATE. На миллионе строк DELETE без условия занял от 0,27 до 2,7 секунды в PostgreSQL и около 1,4 секунды в MySQL, а TRUNCATE уложился в 3–11 миллисекунд.

Сбрасывает ли TRUNCATE автоинкремент?

В MySQL и SQL Server да, нумерация начнётся заново. В PostgreSQL по умолчанию нет: чтобы id снова начинались с единицы, пишите TRUNCATE TABLE имя RESTART IDENTITY.

Как очистить таблицу в MySQL, если на неё ссылается внешний ключ?

TRUNCATE вернёт ошибку 1701. Удалите строки через DELETE FROM имя_таблицы или временно выключите проверку ключей командой SET FOREIGN_KEY_CHECKS = 0 и включите её обратно после очистки.

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

TRUNCATE оставляет пустую таблицу, в которую можно сразу вставлять данные. DROP TABLE удаляет таблицу вместе со структурой, после него запрос к ней вернёт ошибку.

Читайте Checkroi первым в Google
Добавьте Checkroi в избранные источники — и наши разборы курсов и обзоры школ будут показываться выше в вашей выдаче Google.
Оставить комментарий
0 комментариев
Форма комментария

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

Напишите, что думаете. Нам важно ваше мнение!