Как очистить таблицу в Firebird
Короткий ответ
В Firebird нет команды TRUNCATE TABLE — ни в 2.5, ни в 3.0, ни в 4.0, ни в 5.0. Это первое, что нужно принять, если вы пришли из PostgreSQL, MySQL или MSSQL. Вместо неё — три подхода в зависимости от размера таблицы и цели:
DELETE FROM— для маленьких и средних таблиц;- пакетное удаление частями через
EXECUTE BLOCK— для больших; - пересоздание таблицы (
DROP+CREATE) — радикальный вариант для огромных.
Ниже каждый способ с нюансами.
Простой случай: DELETE FROM
DELETE FROM orders_log;
COMMIT;
Для таблицы на тысячи-другую записей этого достаточно. Но помните про побочные эффекты:
- каждая удалённая строка пишется в журнал — на миллионах записей это медленно и раздувает файл базы;
- генераторы (sequences) не сбрасываются — счётчик продолжит с того места, где остановился;
- если по таблице бьются внешние ключи без
ON DELETE CASCADE, удаление упрётся в нарушения.
Сброс генераторов
После очистки часто нужно, чтобы счётчик первичного ключа начался заново:
ALTER SEQUENCE orders_log_id_seq RESTART WITH 0;
В Firebird 2.5 и старше работает устаревший, но живой синтаксис SET GENERATOR orders_log_id_seq TO 0;. Не забудьте: если генератор общий на несколько таблиц (редко, но бывает), сброс сломает уникальность в соседней.
Большая таблица: удаляем частями
Миллионы строк одним DELETE — это длинная транзакция, растущий журнал и страдающий сервер. Правильный путь — удалять порциями с коммитами между ними. Через EXECUTE BLOCK:
EXECUTE BLOCK
AS
BEGIN
WHILE (1=1) DO
BEGIN
DELETE FROM orders_log
WHERE RDB$DB_KEY IN (
SELECT RDB$DB_KEY FROM orders_log ROWS 10000
);
IF (ROW_COUNT = 0) THEN LEAVE;
COMMIT;
END
END
Смысл один: не держать в одной транзакции миллионы изменений. Альтернативы — удалять диапазонами по первичному ключу (WHERE id BETWEEN :a AND :b) с коммитами между частями, или DELETE ... FETCH FIRST n ROWS ONLY в новых версиях.
После полного удаления стоит дать базе собрать мусор — при следующем sweep или явно.
Радикальный вариант: пересоздание
Для очень больших таблиц часто быстрее выгрузить метаданные и пересоздать таблицу:
isql -x база > create_table.sql # выгрузить DDL
DROP TABLE orders_log;
-- выполнить сохранённый DDL
Быстро и чисто, но: данные теряются безвозвратно (очевидно, но напомним), права на таблицу надо выдать заново, зависимые объекты (вьюхи, внешние ключи из других таблиц) пересоздать. Подходит для журналов и логов, содержимое которых не жалко.
Типичные грабли
| Симптом | Причина | Что делать |
|---|---|---|
| DELETE идёт вечность | Миллионы строк в одной транзакции | Пакетное удаление с коммитами |
| Файл базы вырос после удаления | Журнал изменений + не собран мусор | Коммиты порциями, дать sweep |
| После очистки PK продолжается с 100500 | Генераторы не сбрасываются сами | ALTER SEQUENCE ... RESTART WITH 0 |
| Ошибка violation of FOREIGN KEY | Зависимые таблицы без CASCADE | Сначала очистить дочерние или добавить CASCADE |
Что почитать дальше
- EXECUTE BLOCK — анонимные PSQL-блоки, на которых построено пакетное удаление
- DELETE — полный синтаксис оператора
- Таблицы мониторинга — как смотреть на долгие транзакции изнутри
- gbak: резервное копирование — перед массовыми удалениями не помешает свежий бэкап
Обсуждение