← Назад к вопросам
В чем разница между DELETE и TRUNCATE?
1.3 Junior🔥 191 комментариев
#Базы данных (SQL)
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между DELETE и TRUNCATE
Оба оператора удаляют данные из таблицы, но они работают совершенно по-разному. Это важное различие для производительности и восстановления данных.
DELETE — удаление строк
DELETE удаляет строки одну за одной на основе условия WHERE:
DELETE FROM users WHERE id > 100;
DELETE FROM orders; -- Удалит ВСЕ строки
Характеристики DELETE:
- Удаляет построчно
- Может быть WHERE условие
- Создает записи в журнале транзакций (undo log)
- Медленно для больших таблиц
- Можно откатить (ROLLBACK)
- Срабатывают триггеры DELETE
- Счётчик AUTOINCREMENT НЕ сбрасывается
# DELETE с WHERE условием
import sqlite3
conn = sqlite3.connect(':memory:')
cursor = conn.cursor()
cursor.execute('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)')
cursor.execute('INSERT INTO users VALUES (1, "Alice")')
cursor.execute('INSERT INTO users VALUES (2, "Bob")')
cursor.execute('INSERT INTO users VALUES (3, "Charlie")')
# Удалим только одного пользователя
cursor.execute('DELETE FROM users WHERE id = 2')
conn.commit()
# Получим оставшихся
cursor.execute('SELECT * FROM users')
print(cursor.fetchall()) # [(1, 'Alice'), (3, 'Charlie')]
# AUTOINCREMENT НЕ сбросился
cursor.execute('INSERT INTO users (name) VALUES ("David")')
print(cursor.lastrowid) # 4 (не 1)
TRUNCATE — очистка таблицы
TRUNCATE удаляет ВСЕ строки из таблицы как одну операцию:
TRUNCATE TABLE users;
TRUNCATE TABLE orders;
Характеристики TRUNCATE:
- Удаляет все строки сразу (операция на уровне DDL, не DML)
- БЕЗ WHERE условия (нельзя выбрать, какие строки удалить)
- Минимум логирования (очень быстро)
- Сложнее откатить (в некоторых БД)
- НЕ срабатывают триггеры DELETE
- Счётчик AUTOINCREMENT СБРАСЫВАЕТСЯ (в большинстве БД)
-- TRUNCATE в PostgreSQL
TRUNCATE TABLE users;
-- В MySQL
TRUNCATE TABLE users;
-- В SQLite (нет TRUNCATE, используют DELETE или оптимизированный DELETE)
DELETE FROM users;
Таблица сравнения
| Аспект | DELETE | TRUNCATE |
|---|---|---|
| Тип операции | DML (Data Manipulation) | DDL (Data Definition) |
| WHERE условие | Да | Нет |
| Скорость | Медленно | Очень быстро |
| Undo логирование | Да (для каждой строки) | Минимум |
| Откатываемость | Легко (ROLLBACK) | Сложнее (в некоторых БД) |
| Триггеры | Срабатывают | НЕ срабатывают |
| AUTOINCREMENT | НЕ сбрасывается | Сбрасывается |
| Блокировки | Row-level locks | Table lock |
| Пример | DELETE FROM users WHERE id > 100 | TRUNCATE TABLE users |
Примеры на разных БД
PostgreSQL:
-- DELETE
DELETE FROM users WHERE created_at < '2020-01-01';
-- TRUNCATE
TRUNCATE TABLE users; -- Сбросит AUTOINCREMENT
TRUNCATE TABLE users RESTART IDENTITY; -- Явный сброс
-- Откатываемость
BEGIN;
TRUNCATE TABLE users;
ROLLBACK; -- Можно откатить
MySQL:
-- DELETE
DELETE FROM users WHERE status = 'inactive';
-- TRUNCATE
TRUNCATE TABLE users;
-- Внимание: в MySQL TRUNCATE не срабатывает в транзакции
-- Его нельзя откатить!
SQLite:
-- SQLite не имеет TRUNCATE, но есть оптимизированный DELETE
DELETE FROM users; -- Очень быстро в SQLite
-- Или вручную сброс autoincrement
DELETE FROM sqlite_sequence WHERE name = 'users';
Производительность: реальный пример
import time
import sqlite3
conn = sqlite3.connect(':memory:')
cursor = conn.cursor()
cursor.execute('CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)')
# Вставим 1 млн строк
print("Вставляем 1 млн строк...")
for i in range(1_000_000):
cursor.execute('INSERT INTO test (value) VALUES (?)', (f'value_{i}',))
conn.commit()
# DELETE
conn2 = sqlite3.connect(':memory:')
cursor2 = conn2.cursor()
cursor2.execute('CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)')
for i in range(1_000_000):
cursor2.execute('INSERT INTO test (value) VALUES (?)', (f'value_{i}',))
conn2.commit()
print("\nУдаление с DELETE FROM...")
start = time.time()
cursor2.execute('DELETE FROM test')
conn2.commit()
print(f"DELETE: {time.time() - start:.2f}сек")
# TRUNCATE (SQLite не имеет, но покажу логику)
print("\nТRUNCATE был бы быстрее (1-2мс)")
Когда использовать DELETE
# DELETE используй, когда:
# 1. Нужно удалить условные данные
cursor.execute('DELETE FROM logs WHERE created_at < ? AND level = "DEBUG"',
(old_date,))
# 2. Нужна откатываемость
try:
cursor.execute('DELETE FROM important_data WHERE id = ?', (1,))
conn.commit()
except Exception as e:
conn.rollback()
print(f"Ошибка: {e}")
# 3. Нужно срабатывать триггеры
cursor.execute('DELETE FROM users WHERE status = "deleted"')
# Триггер может логировать удаления
Когда использовать TRUNCATE
-- TRUNCATE используй, когда:
-- 1. Нужно очистить таблицу полностью и быстро
TRUNCATE TABLE audit_logs; -- Удалит 10млн строк за 1мс
-- 2. Нужно сбросить AUTOINCREMENT
TRUNCATE TABLE sessions RESTART IDENTITY;
-- 3. Это служебная таблица, где откатываемость не критична
TRUNCATE TABLE temp_calculations;
-- 4. Нужно освободить место на диске
TRUNCATE TABLE large_table; -- Физически освободит место
Практический пример: архивирование логов
import sqlite3
from datetime import datetime, timedelta
conn = sqlite3.connect('app.db')
cursor = conn.cursor()
# Архивируем старые логи
archive_date = datetime.now() - timedelta(days=30)
# Сначала переместим в архив
cursor.execute('''
INSERT INTO logs_archive
SELECT * FROM logs WHERE created_at < ?
''', (archive_date,))
conn.commit()
# Затем удалим из основной таблицы
cursor.execute('DELETE FROM logs WHERE created_at < ?', (archive_date,))
conn.commit()
print(f"Заархивировано логов: {cursor.rowcount}")
# После этого можно очистить VACUUM для освобождения места
cursor.execute('VACUUM')
Вывод
DELETE:
- Используй для селективного удаления (с WHERE)
- Когда нужна откатываемость
- Когда должны срабатывать триггеры
- Медленнее, но безопаснее
TRUNCATE:
- Используй для полной очистки таблицы
- Когда нужна максимальная скорость
- Когда нужно сбросить AUTOINCREMENT
- Не забывай о отсутствии отката в некоторых БД