Iceberg, Delta и Lance: lakehouse-форматы
Parquet-файл на S3 — это удобно, но это не таблица в полном смысле. У набора Parquet-файлов нет атомарных транзакций, нет истории версий, нет согласованного представления при одновременной записи. Lakehouse-форматы — Apache Iceberg, Delta Lake и Lance — добавляют над Parquet-файлами слой метаданных, который превращает «папку с файлами» в настоящую таблицу с ACID, эволюцией схемы и путешествием во времени. DuckDB читает все три через расширения iceberg, delta и lance. Этот урок про то, что такое lakehouse-формат, зачем он нужен и как DuckDB с ним работает.
Проблема голых Parquet-файлов
Представьте таблицу как папку Parquet-файлов на S3. Что не так?
Нет атомарности. Вы дописываете данные — добавляете три файла. Между добавлением первого и третьего другой запрос видит таблицу в полусогласованном состоянии: часть новых данных есть, часть нет. Удаление строк ещё хуже — Parquet нельзя редактировать на месте, файл надо переписать целиком.
Нет истории. Перезаписали файл — старая версия исчезла. Воспроизвести вчерашнее состояние таблицы невозможно. Откатить ошибочную запись нечем.
Нет согласованного списка файлов. Чтобы прочитать таблицу, надо знать, какие файлы в неё входят прямо сейчас. Если кто-то пишет, а кто-то читает, листинг папки даёт несогласованную картину.
Lakehouse-формат закрывает эти дыры одним приёмом: рядом с Parquet-файлами данных он хранит метаданные — отдельные файлы (или записи в каталоге), которые описывают, какие файлы данных входят в таблицу, какова её схема, и какие были снимки (snapshots) состояния во времени.
Apache Iceberg
Apache Iceberg: каталог и иерархия метаданных Delta Lake: архитектура Transaction Log Trino: Iceberg connector — каталоги, метаданные, snapshotsIceberg — табличный формат, родившийся в Netflix и ставший проектом Apache. Он популярен в больших озёрах данных и поддерживается множеством движков: Spark, Trino, Flink, DuckDB.
Метаданные Iceberg — иерархия файлов. На вершине metadata file (JSON) описывает таблицу и список снимков. Каждый снимок ссылается на manifest list, а тот — на manifest files, которые перечисляют конкретные Parquet-файлы данных вместе со статистикой по ним. Запись новой версии создаёт новый набор метаданных и атомарно переключает указатель на актуальный metadata file. Старые снимки остаются — отсюда путешествие во времени.
DuckDB читает Iceberg через расширение iceberg:
INSTALL iceberg;
LOAD iceberg;
-- Чтение таблицы Iceberg
SELECT * FROM iceberg_scan('s3://lake/warehouse/sales') LIMIT 5;
-- Метаданные снимков таблицы
SELECT * FROM iceberg_snapshots('s3://lake/warehouse/sales');
Начиная с DuckDB 1.4 расширение iceberg умеет не только читать, но и писать Iceberg-таблицы. Это важный сдвиг: раньше DuckDB был для Iceberg только потребителем, теперь — и поставщиком.
Delta Lake
Delta Lake — табличный формат из экосистемы Databricks (Apache-проект). Идея та же, что у Iceberg, но устройство метаданных другое.
Сердце Delta — transaction log (папка _delta_log). Это упорядоченная последовательность JSON-файлов, каждый из которых — одна транзакция: «добавлены такие-то файлы», «удалены такие-то». Состояние таблицы на любой момент — это лог, проигранный от начала до нужной транзакции. Периодически лог сворачивается в Parquet-checkpoint, чтобы не проигрывать его весь.
DuckDB читает Delta через расширение delta:
INSTALL delta;
LOAD delta;
-- Чтение Delta-таблицы
SELECT region, SUM(amount) FROM delta_scan('s3://lake/delta/orders') GROUP BY region;
Расширение delta ориентировано прежде всего на чтение. Для записи Delta в экосистеме обычно используют Spark или библиотеку delta-rs.
Lance
Lance — самый молодой из трёх и решает другую задачу. Iceberg и Delta заточены под классическую табличную аналитику. Lance — колоночный формат, оптимизированный под машинное обучение и поиск: быстрый случайный доступ к строкам, эффективное хранение векторных эмбеддингов, встроенная поддержка векторных индексов. Это формат для датасетов ML и для приложений на векторном поиске.
Поддержку Lance DuckDB получил в версии 1.5.1 через расширение lance. Это делает DuckDB удобным SQL-фронтендом к ML-датасетам: данные лежат в Lance-формате, а запрашиваются обычным SQL.
INSTALL lance;
LOAD lance;
-- Чтение Lance-датасета
SELECT * FROM lance_scan('embeddings.lance') LIMIT 10;
Что lakehouse-формат даёт сверх Parquet
Сведём воедино, ради чего весь этот слой метаданных:
Атомарность и согласованность. Запись новой версии — атомарное переключение метаданных. Читатель всегда видит либо старую версию целиком, либо новую целиком, никогда не половину.
Путешествие во времени (time travel). Старые снимки сохраняются, и можно запросить таблицу «как она выглядела вчера» или на конкретный snapshot. Это аудит, отладка, воспроизводимость и откат ошибочных записей.
Эволюция схемы. Добавить, удалить, переименовать колонку — операция над метаданными, не переписывание всех файлов данных. Старые файлы остаются совместимыми через сопоставление по идентификаторам полей.
Эффективное удаление и обновление. Вместо переписывания Parquet-файлов целиком форматы используют delete-файлы или deletion vectors — компактные структуры, помечающие удалённые строки.
Pushdown через метаданные. В метаданных есть статистика по файлам данных. DuckDB по ней отсекает целые файлы ещё до их открытия — как partition pruning, но на уровне табличного формата.
| Возможность | Голые Parquet | Iceberg / Delta / Lance |
|---|---|---|
| Атомарная запись | Нет | Да |
| История версий, time travel | Нет | Да |
| Эволюция схемы без переписи данных | Нет | Да |
| Удаление строк без переписи файлов | Нет | Да (delete-файлы / deletion vectors) |
| Согласованный список файлов таблицы | Нет (листинг папки) | Да (через метаданные) |
У DuckDB Labs есть и собственный lakehouse-формат — DuckLake, достигший версии 1.0 в апреле 2026. Его ключевое отличие от Iceberg и Delta: метаданные хранятся не в разбросанных JSON/Avro-файлах, а в обычной SQL-базе данных (SQLite, PostgreSQL или самой DuckDB). Это даёт атомарные транзакции сразу над несколькими таблицами и быстрые запросы к метаданным без обхода объектного хранилища. DuckLake — отдельная большая тема, ему посвящён модуль про DuckDB everywhere.
Расширения lakehouse-форматов развиваются быстро, и набор возможностей зависит от версии DuckDB и версии расширения. Запись Iceberg появилась только в 1.4; поддержка Lance — только с 1.5.1; deletion vectors и тонкости эволюции схемы поддержаны не во всех комбинациях версий. Перед тем как опираться на конкретную возможность в продакшене, сверяйтесь с документацией расширения под вашу версию DuckDB — здесь особенно легко принять желаемое за действительное.
Попробуй сам
Для знакомства с lakehouse-форматами не нужен большой кластер.
- Установите расширения:
INSTALL iceberg; INSTALL delta;. Проверьте черезduckdb_extensions(), что они появились. - Найдите публичный учебный датасет в формате Iceberg или Delta (такие есть в документации DuckDB и в открытых репозиториях). Прочитайте его через
iceberg_scan(...)илиdelta_scan(...). - Для Iceberg-таблицы выполните
iceberg_snapshots(...)и посмотрите список снимков: у каждого свой идентификатор и временная метка. Это и есть основа time travel. - Сравните по документации, какие файлы лежат внутри Iceberg-таблицы (metadata, manifest list, manifest) и внутри Delta-таблицы (папка
_delta_logс JSON-транзакциями). Сформулируйте, почему оба подхода решают одну задачу — согласованный список файлов и историю — но устроены по-разному.
Apache Iceberg: таблицы поверх файлов — полная архитектура