DuckDB и Apache Iceberg
Лейкхаус без кластера
Содержание

Пятьдесят мегабайт бинарника, миллисекундный старт, никакого JVM и координатора — просто скачал, загрузил расширение, и пишешь SQL прямо против таблиц в S3. С версии 1.5.3 (май 2026) DuckDB умеет не только читать Iceberg, но и писать: MERGE INTO, ALTER TABLE, спецификацию Iceberg V3 и партиционные трансформы. Впервые один встраиваемый движок тянет и чтение, и запись продакшн-таблиц.
Я уже пробовал работать DuckDB к айсбергу, когда знакомился с технологией Apache Iceberg на примере Trino и Nessie
Но ни один движок не работает в вакууме. Продакшн-лейкхаусы держат DuckDB рядом со Spark, Trino, Athena и Snowflake — каждый заточен под свой тип нагрузки. Вопрос не в том, использовать ли DuckDB, а в том, где он сидит в стеке, как держать таблицы оптимизированными под его паттерны запросов и как маршрутизировать правильные запросы в правильный движок.
Полезно думать о трёх слоях, которые не заменяют друг друга:
- Движок запросов (DuckDB) — как ты запускаешь SQL. Встраиваемый, стартует за миллисекунды, без кластера.
- Формат таблиц + каталог (Iceberg) — как данные хранятся, версионируются и обнаруживаются. Общий для всех движков.
- Слой обслуживания — как таблицы остаются здоровыми: компактирование, полная последовательность обслуживания, классификация проблем, политики и маршрутизация.
DuckDB отлично делает слой 1 и совсем не делает слой 3. Когда запрос вдруг замедляется в 10 раз, причина почти никогда не в движке — это раскладка файлов, долг от delete-файлов, устаревшая статистика или таблица, которую никто не обслуживает. Ниже пройдёмся по всем трём слоям.
flowchart LR A[Объектное хранилище<br/>Parquet-файлы] --> B[Таблицы Iceberg] B --> C[Каталог<br/>Glue / REST / S3 Tables] C --> D[DuckDB] C --> E[Spark] C --> F[Trino] C --> G[Athena] D --> H[Слой обслуживания] F --> H H --> B
Почему DuckDB для Iceberg
DuckDB — встраиваемая аналитическая база данных. Она работает внутри твоего процесса — Python, R, Node.js, Go, Java или standalone CLI — без внешних зависимостей. Нет сервера для запуска, нет кластера для масштабирования, нет сетевых задержек между приложением и движком.
Для Iceberg-нагрузок ключевое вот что:
- Миллисекундный старт. DuckDB инициализируется за миллисекунды. Spark — от секунд до минут в зависимости от состояния кластера. Для интерактивных запросов, работы в ноутбуке и валидации в CI/CD эта разница определяет ощущение от инструмента.
- Векторное колоночное выполнение. DuckDB обрабатывает данные колоночными векторами, читая row-группы Parquet напрямую. Вместе с метаданными Iceberg это значит, что DuckDB пропускает нерелевантные файлы и row-группы ещё до того, как коснётся данных.
- 50-мегабайтный размер. Весь движок вместе с расширением Iceberg помещается в один бинарник. Никакой настройки JVM-хипа, shuffle-сервиса или конфигурации исполнителей.
- Полный SQL. Оконные функции, CTE, коррелированные подзапросы, lateral join,
QUALIFY,PIVOT, регулярные выражения — весь аналитический диалект. - Нативная интеграция с Python.
import duckdbдаёт внутрипроцессный движок, который в одном SQL-выражении умеет опрашивать Pandas DataFrame, Arrow-таблицы и Iceberg-таблицы.
Релиз 1.5.3 закрыл последнюю большую дыру: DuckDB теперь может писать в Iceberg через любой REST-каталог — INSERT, UPDATE, DELETE, MERGE INTO, ALTER TABLE и создание партиционированных таблиц. DuckDB больше не «только чтение» для Iceberg.
Подключение к каталогам Iceberg
Расширение Iceberg ставится автоматически при первом использовании. Для таблиц на S3 нужны ещё httpfs и, на AWS, расширение aws:
INSTALL iceberg;LOAD iceberg;INSTALL httpfs;LOAD httpfs;INSTALL aws;LOAD aws;
DuckDB поддерживает два режима доступа к Iceberg: сканирование по пути (только чтение) и таблицы через каталог (полный доступ на запись).
Сканирование по пути через iceberg_scan
Самый простой способ запросить таблицу — указать iceberg_scan на её хранилище:
SELECT order_date, SUM(total) AS revenueFROM iceberg_scan('s3://my-bucket/warehouse/orders/')WHERE order_date >= '2026-01-01'GROUP BY order_dateORDER BY revenue DESC;
DuckDB читает метаданные Iceberg, определяет, какие файлы данных подходят под предикат, и сканирует только нужные Parquet-файлы. Каталог не требуется — удобно для быстрой разведки, разовых анализов или окружений, где доступ к каталогу ограничен. Сканирование по пути не умеет писать.
Подключение REST-каталога
Для продакшена — и для любых операций записи — подключай REST-каталог Iceberg. Большинство каталогов авторизуются через OAuth2:
CREATE SECRET iceberg_secret ( TYPE ICEBERG, CLIENT_ID 'admin', CLIENT_SECRET 'password', OAUTH2_SERVER_URI 'https://catalog.example.com/v1/oauth/tokens'); ATTACH 'warehouse' AS my_lake ( TYPE ICEBERG, SECRET iceberg_secret, ENDPOINT 'https://catalog.example.com');
После подключения каталог ведёт себя как обычная база DuckDB. Таблицы адресуются как catalog.schema.table и поддерживают весь SQL — SELECT, INSERT, UPDATE, DELETE, MERGE INTO и ALTER TABLE.
Свежесть каталога
DuckDB кэширует метаданные таблицы при подключении. Если Spark, Flink или Firehose закоммитят новые снапшоты, пока сессия открыта, последующий SELECT может вернуть устаревший снапшот. В долгоживущих процессах важны два рычага:
MAX_TABLE_STALENESSнаATTACH— как долго DuckDB может переиспользовать метаданные каталога перед обновлением (например,'10 minutes').- Переподключение или обновление после коммита внешнего писателя, если нужен свежий снапшот немедленно.
Это частая неожиданность в проде: ноутбук в 9:00 выглядит корректно, стриминговый джоб пишет в 9:05, а та же сессия DuckDB продолжает читать данные 9:00. Подключение к каталогу — это не живая подписка.
Чтение: паттерны запросов, которые остаются быстрыми
Когда каталог подключён, таблицы Iceberg — обычный SQL. Разница между запросом на 200 мс и на 20 секунд почти всегда в отсечении по метаданным, а не в движке выполнения.
SELECT customer_id, SUM(total) AS revenueFROM my_lake.sales.ordersWHERE order_date BETWEEN '2026-08-01' AND '2026-08-07' AND country = 'US'GROUP BY customer_idORDER BY revenue DESCLIMIT 20;
Как это работает. DuckDB заранее смотрит на метаданные Iceberg и статистику row-групп Parquet и отсекает лишнее до того, как начнёт читать данные. Если колонка в фильтре партиционирована или отсортирована, движок сразу пропускает целые файлы и row-группы — читать байты вообще не приходится. А вот фильтр по обычной колонке (не партиционированной и не отсортированной) заставляет сканировать больше данных: сам движок не тормозит, но читает слишком много.
Если скан медленнее ожидаемого, загляни в метаданные:
SELECT * FROM iceberg_snapshots(my_lake.sales.orders);SELECT file_path, record_count, contentFROM iceberg_metadata(my_lake.sales.orders);
iceberg_snapshots показывает историю. iceberg_metadata — сканируешь ли ты сотни мелких файлов или компактный набор крупных; это первая диагностика, когда DuckDB «внезапно» замедлился.
Time travel и снапшоты
Коммиты Iceberg — это снапшоты. DuckDB может запросить любое историческое состояние по id снапшота или метке времени — из таблицы каталога или через iceberg_scan:
-- Таблица из каталогаSELECT *FROM my_lake.sales.orders AT (VERSION => 8027658604211071520); SELECT *FROM my_lake.sales.orders AT (TIMESTAMP => '2026-08-01 12:00:00'); -- Сканирование по путиSELECT count(*)FROM iceberg_scan( 's3://my-bucket/warehouse/orders/', snapshot_from_id := 8027658604211071520);
Time travel — это функция чтения, а не политика хранения. Пока снапшоты живут, старые файлы и манифесты никто не удаляет — они занимают место на диске. Для аудита и откатов это удобно. Но если чистить снапшоты по расписанию никто не будет, счёт за хранение будет расти месяц за месяцем.
Запись: что открывает версия 1.5.3
До версии 1.5.3 DuckDB мог только читать Iceberg — запись не поддерживалась. Теперь появился и слой записи, которого не хватает многим продакшн-задачам. Правда, с ограничениями, о которых стоит знать.
Создание таблиц и INSERT
Создавай партиционированные таблицы Iceberg обычным SQL, включая bucket- и truncate-трансформы, появившиеся в 1.5.3:
CREATE TABLE my_lake.analytics.events ( event_id BIGINT, user_id BIGINT, country VARCHAR, event_type VARCHAR, event_time TIMESTAMP)PARTITIONED BY (bucket(16, user_id), truncate(2, country)); INSERT INTO my_lake.analytics.events VALUES (1, 1001, 'RU', 'click', '2026-08-01 12:00:00'), (2, 1002, 'US', 'view', '2026-08-01 12:05:00');
Подбирай партиции под фильтры, которые реально гоняешь. Высококардинальный bucket по user_id помогает точечным поискам. Дата или усечённая страна — диапазонным и размерным фильтрам. Стратегия партицирования, не совпадающая с предикатами запросов, не даёт DuckDB ничего отсекать.
MERGE INTO для апсертов
MERGE INTO закрывает апсерты — самый частый паттерн записи в CDC- и slowly changing dimension-процессах:
MERGE INTO my_lake.analytics.customers AS target USING staging_updates AS source ON source.customer_id = target.customer_id WHEN MATCHED THEN UPDATE SET * WHEN NOT MATCHED THEN INSERT *;
MERGE INTO использует семантику merge-on-read: совпавшие строки записываются как позиционные удаления, а новые версии — как файлы данных. Такой же подход используют Spark и Trino, поэтому итоговое состояние таблицы интероперабельно между движками.
Эволюция схемы
ALTER TABLE теперь работает c Iceberg-таблицами – добавление, переименование и удаление колонок и переименование таблиц без переписывания данных:
ALTER TABLE my_lake.analytics.events ADD COLUMN device VARCHAR;ALTER TABLE my_lake.analytics.events RENAME COLUMN event_type TO action;ALTER TABLE my_lake.analytics.events DROP COLUMN device;
Изменения схемы в Iceberg – правка метаданных. DuckDB обновляет id текущей схемы в метаданных таблицы, и изменения сразу видны любому другому движку, подключённому к тому же каталогу.
Поддержка Iceberg V3
DuckDB 1.5.3 поддерживает спецификацию Iceberg V3: тип VARIANT, точность TIMESTAMP_NS, бинарные векторы удалений и lineage строк. Таблицы V3 кодируют удаления компактными Puffin-файлами вместо Parquet-файлов позиционных удалений — заметно снижая накладные расходы метаданных при частых обновлениях. Типы Geography и Unknown пока не поддерживаются.
CREATE TABLE my_lake.analytics.v3_eventsWITH ('format-version' = 3) AS SELECT 1 AS id, {'kind': 'click', 'x': 10}::VARIANT AS payload, TIMESTAMP_NS '2026-08-01 12:00:00.123456789' AS event_time;
Ограничения записи, которые всё ещё действуют
Запись идёт через подключённый каталог — iceberg_scan остаётся read-only. UPDATE, DELETE и MERGE INTO пишут позиционные удаления (merge-on-read), а не copy-on-write. Поэтому частые апсерты накапливают долг delete-файлов, который каждый последующий скан DuckDB обязан применять. Это ожидаемое поведение Iceberg, а не баг DuckDB — и именно поэтому компактирование должно жить в одной ментальной модели с записью.
Налог от delete-файлов на чтение
Каждый MERGE, UPDATE или DELETE, закоммиченный DuckDB (или Spark, или Flink), добавляет delete-файлы. При следующем чтении DuckDB обязан загрузить эти удаления и отфильтровать совпавшие строки из файлов данных. Горстка delete-файлов — дёшево. Тысячи — типичный результат ночного CDC — превращают векторный скан в «сначала примени удаления, потом сканируй».
Это та же проблема merge-on-read, с которой сталкивается каждый Iceberg-движок. DuckDB не компактит delete-файлы. Если используешь DuckDB как писателя для апсертов, всё равно нужен процесс обслуживания, который переписывает файлы данных и сбрасывает применённые удаления. Иначе движок, казавшийся мгновенным в первый день, деградирует с каждым успешным MERGE.
Производительность: почему раскладка таблицы определяет скорость
DuckDB быстр, потому что читает Parquet напрямую с векторным выполнением, — но эта скорость целиком зависит от того, как организованы лежащие файлы. Раскладка таблицы — самый большой рычаг производительности запросов DuckDB, и именно это измерение большинство команд упускают.
Проблема мелких файлов
Любая Iceberg-таблица начинается как набор Parquet-файлов в объектном хранилище. Каждый запрос должен прочитать метаданные, определить релевантные файлы и достать их по сети. Если в таблице 50 000 мелких файлов (типично после стриминговой загрузки или частых мелких записей), DuckDB отправляет 50 000 HTTP GET к S3 — и накладные расходы I/O доминируют над общим временем запроса независимо от скорости движка.
Компактирование сливает мелкие файлы в крупные (256–512 МБ оптимальны для большинства нагрузок). После сжатия та же таблица может иметь 200 файлов вместо 50 000. DuckDB сканирует её за секунды вместо минут.
Порядок сортировки и отсечение по предикатам
Файлы Parquet содержат статистики min/max по row-группе и по колонке. Когда данные отсортированы по колонкам, по которым ты фильтруешь, отсечение по предикатам пропускает целые row-группы без чтения. WHERE event_date = '2026-08-01' на отсортированной по дате таблице читает долю данных, которую тот же запрос читает на неотсортированной.
Загвоздка: оптимальный порядок сортировки зависит от того, как таблицу реально опрашивают, и разные движки могут опрашивать её по-разному. Порядок, оптимальный для Trino-дашбордов, может не подойти для ad-hoc-разведки в DuckDB.
Здесь в дело вступает осмысленное компактирование. Анализируй фактические паттерны запросов по всем движкам — включая DuckDB — и определяй оптимальный порядок сортировки для каждой таблицы. Симуляции раскладки предсказывают сокращение скана разных стратегий сортировки ещё до записи байта. Результат: файлы ложатся под то, как таблицу реально опрашивают, а не под чью-то догадку на этапе пайплайна.
Скорость и цена компактирования
Компактирование — не бесплатное. Spark-компактирование таблицы на 200 ГБ занимает ~1600 секунд и стоит примерно 3000₽/ТБ. Rust/DataFusion-движок делает тот же binpack за 221 секунду при ~300₽/ТБ — примерно в 7 раз быстрее и на порядок дешевле. Sort-компактирование, переписывающее файлы в оптимальном порядке для отсечения предикатов, даёт ещё больший выигрыш, потому что Rust-движок обрабатывает Parquet напрямую, без накладных расходов java машины — тот же «без кластера» подход, что и у DuckDB, только применительно к обслуживанию.
Дело не только в более быстром сжатии. Компактирование ускоряет запросы DuckDB. Хорошо сжатые, правильно отсортированные таблицы со свежей статистикой колонок – фундамент производительности DuckDB на Iceberg. Без них ты меряешь ввод-вывод, а не скорость движка запросов.
Когда DuckDB, а когда Spark, Trino, Athena
Каждый движок заточен под свой профиль нагрузки. Использование не того движка ради работы тратит либо деньги, либо время — обычно оба.
| Измерение | DuckDB | Spark | Trino | Athena |
|---|---|---|---|---|
| Развёртывание | Встраиваемый, в процессе | Распределённый кластер | Распределённый кластер | Serverless |
| Старт | Миллисекунды | Секунды–минуты | Секунды | Секунды |
| Лучше всего для | Интерактивные запросы, ноутбуки, CI/CD, малые/средние данные | Тяжёлый ETL, крупные трансформации, ML-пайплайны | Конкурентные дашборды, федеративные запросы | Ad-hoc serverless SQL |
| Конкурентность | Однопользовательский (встраиваемый) | Высокая (распределённый) | Высокая (распределённый) | Умеренная (цена за запрос) |
| Поддержка записи | Полная (1.5.3, REST-каталог) | Полная | Полная | Ограниченная (INSERT, CTAS) |
| Модель цены | Бесплатный (open source) | Стоимость кластера | Стоимость кластера | $5/ТБ скана |
| Макс. размер данных | Память + диск одного узла | Петабайты | Петабайты | Петабайты |
| Интеграция с Python | Нативная (в процессе) | PySpark (клиент-сервер) | JDBC/REST | JDBC/REST |
Где DuckDB выигрывает
- Интерактивная разведка: дата-сайентист открывает ноутбук, импортирует DuckDB и опрашивает Iceberg-таблицы в S3 без разворачивания чего-либо. Цикл обратной связи — миллисекунды, а не минуты.
- Валидация данных в CI/CD: DuckDB работает внутри GitHub Action или CI-пайплайна для проверки схем таблиц, контроля качества данных и генерации тестовых отчётов — без поднятия кластера.
- Малая и средняя аналитика: для данных, умещающихся в память одного узла (до сотен гигабайт со spill-to-disk), DuckDB не уступает или обгоняет распределённые движки, потому что не тратит время на координацию, shuffle и сеть.
- Прототипирование и разработка: тестируй трансформации локально до деплоя в Spark или Trino в проде.
- Вызовы ИИ-агентов: короткие, ограниченные SQL из цикла агента. Профиль старта и задержки DuckDB лучше ложится в формат «запрос—ответ», чем прогрев кластера.
Где DuckDB не подходит
- Тяжёлый ETL в масштабе: многотерабайтные трансформации, требующие распределённого shuffle и параллельной записи в сотни партиций. Распределённая модель Spark существует не просто так — и замена Spark только для компактирования это другое решение, чем замена Spark для ETL.
- Высококонкурентное обслуживание: DuckDB встраиваемый и однопроцессный. Он не вытягивает сотни конкурентных дашборд-запросов так, как Trino или Snowflake.
- Стриминговое вливание: Flink и Spark Structured Streaming тянут непрерывный micro-batch в Iceberg. DuckDB пакетный.
Реальность такая: большинство прод-команд гоняет несколько движков одновременно. DuckDB — ноутбуки и ad-hoc. Spark — ETL. Trino — дашборды. Вопрос в том, как направить нужный запрос в нужный движок без захардкоженного решения в коде приложения.
Маршрутизация запросов между движками
В многодвижковом лейкхаусе задача маршрутизации обманчиво сложна. У каждого движка свои нюансы SQL-диалекта, своя модель цены и свои характеристики задержки. Команды обычно начинают с захардкоженного выбора движка — Spark для этого пайплайна, Trino для того дашборда, DuckDB для ad-hoc — и накапливают технический долг по мере эволюции ландшафта.
Нормальному слою маршрутизации нужно уметь диспетчеризацию SQL, перевод диалектов, failover по состоянию здоровья и выбор движка по стоимости. Ещё нужны стабильные endpoints, чтобы приложения не ломались, когда ты добавляешь более быстрый движок или убираешь старый.
Маршрутизационные группы сопоставляют типы нагрузки с пулами движков, с приоритетом и логикой failover:
- Analytics (интерактивный, ad-hoc) → DuckDB + Trino, DuckDB предпочтителен для субсекундных запросов
- BI (дашборды, отчёты) → Trino + Snowflake, оптимизирован под конкурентный доступ
- ETL (трансформации, пайплайны) → Spark + Athena, оптимизирован под пропускную способность
- ИИ-агенты → DuckDB + Trino через MCP, с лимитами стоимости и guardrails
flowchart LR A[Приложение] --> B[Слой маршрутизации] B --> C[Analytics<br/>DuckDB + Trino] B --> D[BI<br/>Trino + Snowflake] B --> E[ETL<br/>Spark + Athena] C --> F[Таблицы Iceberg] D --> F E --> F
Приложения получают стабильный endpoint на группу маршрутизации. Когда добавляешь DuckDB в analytics-пул или убираешь непродуктивный движок, слой маршрутизации поглощает изменение. Никаких правок в коде приложения и миграций endpoints.
Что DuckDB не делает: обслуживание в проде
DuckDB — движок запросов. Он читает и пишет данные. Продакшн-таблицам Iceberg нужен слой непрерывной эксплуатации, который не даёт ни один движок запросов, — и именно здесь большинство команд недоинвестируют.
Обслуживание таблиц
Каждая Iceberg-таблица копит эксплуатационный долг: мелкие файлы от стриминговой записи, протухшие снапшоты, съедающие хранилище, orphan-файлы от упавших джобов, манифесты, растущие глубже с каждым коммитом. Полная последовательность обслуживания — протухание снапшотов, удаление orphan-файлов, сжатие файлов данных, переписывание манифестов, пересчёт статистики колонок — должна выполняться в правильном порядке зависимостей, непрерывно, по всем таблицам.
DuckDB не запускает обслуживание. Trino и Athena тоже. Spark может гонять компактирование через хранимые процедуры, но планирование, мониторинг и выстраивание последовательности для сотен таблиц — отдельная инженерная задача, которая масштабируется вместе с лейкхаусом, а не с запросной нагрузкой.
Наблюдаемость
Когда запрос DuckDB внезапно замедляется в 10 раз, начинай с таблицы: число файлов, доля delete-файлов, накопление снапшотов, перекос партиций, устаревшая статистика. Без мониторинга здоровья на уровне таблиц диагностика превращается в гадание — и ты будешь крутить SQL, вместо того чтобы сжать файлы.
Операционный слой
Тем, кто не хочет собирать слой обслуживания руками, стоит посмотреть в сторону инструментов операционной плоскости, которые закрывают именно этот пробел. Автономное обслуживание прогоняет полную последовательность в правильном порядке зависимостей. Классификация проблем подсвечивает деградацию таблиц до того, как она доберётся до задержки запроса. Каскадные политики управляют компактированием, хранением и очисткой от каталога к неймспейсу к таблице — заменяя разрозненные Airflow DAG, которые команды копят по мере роста лейкхауса.
Связка простая: DuckDB отвечает за запросы, а слой обслуживания — за всё остальное: обслуживание, маршрутизацию, наблюдаемость, управление. Таблицы остаются компактными, правильно отсортированными и здоровыми. Запросы DuckDB — быстрыми.
Фреймворк решений
Используй DuckDB, когда:
- Нагрузка интерактивная — ноутбуки, ad-hoc SQL, локальная разработка
- Нужен миллисекундный старт — CI-проверки, вызовы агентов, короткоживущие процессы
- Рабочий набор умещается в один узел (память плюс spill-to-disk)
- Нужны чтение и запись через REST-каталог без поднятия Spark
- Python или CLI — естественный интерфейс
Используй Spark, Trino или Athena, когда:
- Трансформации многотерабайтные и требуют распределённого shuffle
- Много конкурентных пользователей бьют в одни дашборды
- Вливание — непрерывный стриминг
- Уже платишь за кластер или serverless-модель скана, подходящую задаче
Добавляй слой обслуживания, когда:
- Запросы DuckDB быстры настолько, насколько быстры раскладка файлов, удаления и статистика
- Запускаешь больше одного движка и не хочешь захардкоженного выбора
- Протухание снапшотов, очистка orphan-файлов и компактирование должны идти по порядку, по всему лейкхаусу
- Хочешь здоровье и политики вместо растущей кучи DAG обслуживания
На практике DuckDB — движок, который ты добавляешь первым для разведки. Слой обслуживания — это то, что держит этот движок честным, когда те же таблицы пишут Spark, Flink, MERGE-джобы и агенты.
Итог
DuckDB делает Iceberg доступным без инфраструктуры. Установил бинарник, подключил каталог, запустил SQL. С версии 1.5.3 он тянет чтение, запись, эволюцию схемы, time travel и апсерты — покрывая полный жизненный цикл многих нагрузок без единого кластера.
Держи в голове модель из трёх слоёв. DuckDB — движок. Iceberg — общая таблица. Слой обслуживания — то, что не даёт delete-файлам, мелким файлам и накоплению снапшотов превратить миллисекундный движок в бенчмарк S3-задержки. Качество компактирования, порядок сортировки и статистика колонок — самые большие рычаги, и они требуют системы обслуживания, работающей непрерывно по всему лейкхаусу. В проде DuckDB — один движок в многодвижковой архитектуре, где маршрутизация, мониторинг здоровья и автономное обслуживание определяют, быстр ли конкретный запрос.
Начни с DuckDB для интерактивных и разработочных нагрузок. Добавь его в группу аналитиков рядом с Trino для субсекундных запросов. Держи лежащие таблицы оптимизированными с помощью осмысленного компактирования. И подключи каталоги, чтобы видеть полную операционную картину по каждому движку, таблице и каталогу лейкхауса.