TRUNCATE в SQL очищает таблицу целиком одной командой: TRUNCATE TABLE orders; Строки исчезают, а сама таблица, её столбцы, индексы и права остаются на месте. DELETE делает похожую работу иначе: удаляет строки по условию WHERE, проходит по ним по одной и вызывает триггеры.
Если нужно удалить часть записей, берите DELETE. Если нужна пустая таблица и никто, кроме вас, с ней сейчас не работает, быстрее TRUNCATE. Ниже синтаксис для пяти СУБД, сравнение по восьми пунктам и замер скорости на миллионе строк. Если вы только начинаете с запросами, сначала прочитайте что такое язык SQL.
Синтаксис 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.
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 |
|---|---|---|---|---|---|
| Нейросети для рабочих задач Перейти на сайт курса | 31 290 ₽ | - | 1 месяц | Обзор курса | |
| SQL для анализа данных Перейти на сайт курса | 52 353 ₽ | 6203 ₽/мес. | 2 месяца | Обзор курса | |
| SQL-разработчик: тариф PRO Перейти на сайт курса | 89 900 ₽ | 7491 ₽/мес. | 2 месяца | Обзор курса | |
| SQL-разработчик: тариф Базовый Перейти на сайт курса | 79 900 ₽ | 3329 ₽/мес. | 3 месяца | Обзор курса | |
| SQL с нуля | 134 640 ₽ | 5500 ₽/мес. | 12 месяцев | Обзор курса |
Больше программ — в полном каталоге курсов по SQL




