EXPORT DATABASE и IMPORT DATABASE для бэкапа и миграции
Файл базы DuckDB можно скопировать как обычный файл — и это рабочий бэкап. Но у такого бэкапа есть ограничение: он привязан к конкретному бинарному формату хранения. EXPORT DATABASE и IMPORT DATABASE дают другой вид бэкапа — логический: вся база выгружается в набор файлов данных плюс SQL-скрипт схемы. Такой дамп переносим между версиями DuckDB и человекочитаем в части схемы. Этот урок разбирает, как это работает и когда какой вид бэкапа выбирать.
Два вида бэкапа: физический и логический
Сначала — различие, без которого тема не складывается.
Физический бэкап — копия файла базы data.db как есть, байт в байт (cp data.db backup.db). Быстро, просто, но это снимок конкретного бинарного формата хранения. Восстановление — обратное копирование.
Логический бэкап — выгрузка содержимого базы в нейтральном виде: данные в Parquet/CSV, схема — в виде SQL-команд CREATE TABLE, CREATE VIEW и т.д. Это не байтовая копия формата, а описание «что в базе есть» на языке, который любая версия DuckDB поймёт. Именно это делает EXPORT DATABASE.
| Физический бэкап (копия файла) | Логический бэкап (EXPORT DATABASE) | |
|---|---|---|
| Что это | байтовая копия файла хранения | данные в Parquet/CSV + SQL-схема |
| Переносимость между версиями | ограничена форматом хранения | высокая — дамп логический |
| Человекочитаемость | нет (бинарный формат) | схема читаема, данные в открытом формате |
| Скорость | очень быстро (просто копирование) | медленнее (выгрузка и пересборка) |
| Назначение | быстрый локальный снимок | миграция, архив, перенос между версиями |
EXPORT DATABASE: выгрузка всей базы
EXPORT DATABASE выгружает всю текущую базу — все таблицы, представления, последовательности, схему — в указанный каталог.
-- выгрузить базу в каталог, данные в Parquet
EXPORT DATABASE 'db_dump' (FORMAT parquet);
-- или в CSV
EXPORT DATABASE 'db_dump_csv' (FORMAT csv);
После выполнения в каталоге db_dump появится несколько файлов:
db_dump/
├── schema.sql -- DDL: CREATE TABLE, CREATE VIEW, CREATE SEQUENCE ...
├── load.sql -- команды COPY для загрузки данных обратно в таблицы
├── customers.parquet
├── orders.parquet
├── products.parquet
└── ... -- по файлу данных на каждую таблицу
Три типа содержимого:
- schema.sql — DDL всей базы: команды создания таблиц, представлений, последовательностей. Это и есть человекочитаемая часть — обычный SQL-скрипт, который можно открыть и прочитать.
- load.sql — команды
COPY, загружающие файлы данных обратно в соответствующие таблицы. - Файлы данных — по одному Parquet- или CSV-файлу на каждую таблицу с её содержимым.
Под капотом EXPORT DATABASE для каждой таблицы выполняет COPY ... TO — то есть это COPY из прошлых уроков, применённый ко всей базе сразу, плюс выгрузка схемы.
IMPORT DATABASE: восстановление из дампа
IMPORT DATABASE восстанавливает базу из каталога, созданного EXPORT DATABASE:
-- в новой (обычно пустой) базе
IMPORT DATABASE 'db_dump';
Одна команда — и DuckDB проигрывает дамп: сначала schema.sql (создаёт все таблицы и представления), затем load.sql (загружает данные из файлов в таблицы). На выходе — база с той же схемой и теми же данными, что были на момент EXPORT DATABASE.
Эквивалент IMPORT DATABASE — выполнить вручную сначала schema.sql, потом load.sql. IMPORT DATABASE просто делает это одной командой:
-- то же, что IMPORT DATABASE 'db_dump', вручную:
.read db_dump/schema.sql
.read db_dump/load.sql
То, что дамп — это просто SQL-скрипты плюс файлы открытого формата, и есть источник его переносимости: восстановить базу можно любой версией DuckDB, которая умеет исполнять этот SQL и читать эти Parquet/CSV.
Главное применение: миграция между версиями
Зачем логический бэкап, если есть простое копирование файла? Ответ — в совместимости версий.
Бинарный формат хранения DuckDB эволюционирует: у каждой линии версий свой номер storage-формата. Backward-совместимость (новая версия читает старый файл) в DuckDB гарантирована начиная с версии 0.10. А вот forward-совместимость (старая версия читает файл, записанный более новой) — лишь best-effort: гарантии нет.
Логический дамп обходит эту проблему целиком. Дамп — это не файл формата, а SQL плюс Parquet. Любая версия DuckDB, читающая SQL и Parquet (то есть любая), восстановит из него базу. Поэтому EXPORT DATABASE / IMPORT DATABASE — рекомендуемый способ:
- Перенести базу между разными версиями DuckDB — особенно когда прямое открытие файла невозможно из-за разницы форматов.
- Долговременно архивировать — дамп не устареет вместе с бинарным форматом.
- Перенести данные между машинами/окружениями — самодостаточный каталог.
Перед обновлением DuckDB на новую мажорную версию сделайте EXPORT DATABASE текущей базы. Это страховка: если новый бинарный формат не откроет старый файл напрямую (или вы захотите вернуться на старую версию), логический дамп позволит восстановить базу на любой стороне. Дамп переживает смену формата хранения, чего не гарантирует копия файла.
Что переживает дамп, а что — нет
Полезно понимать, что именно сохраняется в логическом дампе, а что теряется. schema.sql содержит DDL — определения таблиц, представлений, последовательностей. Это значит, что структура базы воссоздаётся полностью: имена и типы колонок, ограничения (PRIMARY KEY, NOT NULL, CHECK), представления с их SQL-определениями.
А вот что в логический дамп по своей природе не входит: текущее состояние WAL (он и не нужен — дамп делается из закоммиченного состояния), внутренняя физическая раскладка (номера блоков, конкретные row group — при IMPORT всё перестроится заново), статистика и zonemap (они пересоберутся при загрузке данных). Это не потеря: физический слой воссоздаётся новой версией DuckDB с нуля и под её формат, что как раз и есть причина переносимости.
Ещё одно следствие пересборки физического слоя: импортированная база может оказаться компактнее исходной. Если в исходной базе было много обновлений и удалений, накопивших «мусорные» старые версии, то IMPORT DATABASE пишет данные начисто, и фрагментация исчезает. То есть цикл EXPORT -> IMPORT попутно работает как дефрагментация базы.
EXPORT DATABASE против COPY и других механизмов
Чтобы тема встала на место — сравнение с соседними инструментами.
| Механизм | Масштаб | Назначение |
|---|---|---|
COPY ... TO | одна таблица / один запрос | выборочный экспорт результата в файл |
EXPORT DATABASE | вся база (данные + схема) | бэкап, миграция, архив всей базы |
Копия файла .db | вся база (бинарно) | быстрый физический снимок |
ATTACH другой базы | подключение базы как есть | работа с несколькими базами одновременно |
COPY — это «отдать кусок». EXPORT DATABASE — «сохранить всё переносимо». Копия файла — «быстрый снимок без переносимости». Это разные инструменты под разные задачи, и EXPORT DATABASE занимает нишу именно переносимого полного бэкапа.
Существует ещё команда ATTACH ... AS ... (TYPE ...) для копирования базы целиком в новый файл, но для задач бэкапа и миграции между версиями именно пара EXPORT DATABASE / IMPORT DATABASE — канонический инструмент благодаря логической, не привязанной к формату природе дампа.
Попробуй сам
- Создай базу с несколькими таблицами: открой
duckdb mydb.db, создай 2-3 таблицы черезCREATE TABLE ... AS SELECT ... FROM range(...), добавь одно представление черезCREATE VIEW. - Выполни
EXPORT DATABASE 'my_dump' (FORMAT parquet);Посмотри содержимое каталогаmy_dumpв файловой системе — найдиschema.sql,load.sqlи файлы данных. - Открой
schema.sqlтекстовым редактором. Узнаёшь ли своиCREATE TABLEиCREATE VIEW? Это и есть человекочитаемая часть логического дампа. - Создай новую пустую базу (
duckdb fresh.db) и выполни в нейIMPORT DATABASE 'my_dump';Проверь черезSHOW TABLESиSELECT count(*), что таблицы и данные восстановились. - Подумай и сформулируй: в каком сценарии копия файла
mydb.dbсработает как бэкап, а в каком — может не сработать, тогда как логический дамп сработает всегда. Свяжи ответ с forward-совместимостью формата хранения.
dbt snapshots: история изменений данных без логического дампа