MotherDuck: managed cloud DuckDB и dual execution
DuckDB по своей природе — embedded-движок: он живёт внутри вашего процесса, на вашей машине. Это его сила (нет сервера, нет сети, нет администрирования) и одновременно граница: данные лежат там, где запущен процесс, а делиться ими, шедулить запросы по расписанию или масштабировать compute за пределы одного ноутбука встроенными средствами нельзя.
MotherDuck — это коммерческий managed-сервис, который достраивает вокруг DuckDB облачную часть, не превращая DuckDB в обычную клиент-серверную СУБД. Ключевая идея — не «перенести DuckDB на сервер», а dual execution: один и тот же запрос может частично исполниться у вас локально, а частично — в облаке, и движок сам решает, как разделить работу, чтобы данные двигались минимально. В этом уроке разберём, что именно MotherDuck добавляет к DuckDB, как устроен dual execution и когда он реально ускоряет запросы.
Что MotherDuck добавляет к DuckDB
MotherDuck не форк DuckDB и не другой движок. Это тот же DuckDB, обёрнутый в облачную инфраструктуру. Подключение выглядит как ещё одна база, которую вы присоединяете:
-- Локальный DuckDB присоединяет облачный аккаунт MotherDuck
ATTACH 'md:';
-- Теперь видны облачные базы рядом с локальными
SHOW DATABASES;
-- database_name
-- ------------
-- memory -- локальная in-memory
-- my_cloud_db -- база в облаке MotherDuck
-- sample_data -- общий демо-датасет MotherDuck
После ATTACH 'md:' у вас в одной сессии и локальные, и облачные таблицы, и обращаться к ним можно одним запросом. Поверх этого MotherDuck даёт то, чего у embedded-DuckDB нет по определению:
- Хранилище в облаке — базы лежат на стороне сервиса, не на вашем диске; доступны с любой машины, с которой вы подключились.
- Совместный доступ — облачную базу или её часть можно расшарить коллегам; они подключаются к тем же данным.
- Серверный compute — у облака есть собственные вычислительные узлы («ducklings»), которые исполняют запросы независимо от вашего ноутбука.
- Расписание и фоновые задачи — запросы по cron без постоянно включённой локальной машины.
- Веб-интерфейс — UI для запросов; внутри него, кстати, работает DuckDB-WASM из прошлого урока, а результаты кешируются на клиенте.
Важно: с точки зрения SQL вы пишете обычный DuckDB-диалект. Friendly SQL, чтение Parquet, оконные функции — всё то же самое. MotherDuck меняет не язык, а то, где физически крутится исполнение.
MotherDuck — проприетарный сервис, основанный частью команды, причастной к DuckDB. Сам DuckDB остаётся MIT-лицензированным и полностью самодостаточным: MotherDuck не нужен, чтобы пользоваться DuckDB. Это отдельный продукт, который решает задачи «облако, шеринг, расписание» поверх движка.
Проблема, которую решает dual execution
Представьте типичную ситуацию: большая таблица фактов (сотни гигабайт) лежит в облаке MotherDuck, а маленький свежий CSV с локальными правками — у вас на ноутбуке. Вам нужен JOIN между ними. У классической архитектуры два плохих варианта.
Вариант «всё в облаке»: залить локальный CSV в облако, потом исполнить запрос там. Но если CSV меняется каждый раз, заливка — постоянные накладные расходы.
Вариант «всё локально»: скачать сотни гигабайт облачной таблицы на ноутбук и соединить локально. Это бессмысленно — тащить терабайт по сети ради JOIN с маленьким файлом.
Правильный ответ очевиден человеку: тяжёлую часть (сканирование и предагрегацию большой таблицы) надо делать там, где эта таблица лежит, — в облаке, а в обмене по сети должен участвовать только маленький результат. Dual execution автоматизирует ровно это рассуждение.
Как работает dual execution
Dual execution (его также называют hybrid execution) — это способность одного запроса исполняться частично локально и частично в облаке. Решение принимает оптимизатор: он строит план запроса и для каждого фрагмента определяет, на какой стороне его выполнить.
Логика решения сводится к одному принципу — минимизировать перемещение данных. Оператор стремится исполниться там, где находятся его входные данные:
- Скан большой облачной таблицы и фильтры/агрегации над ней — в облаке, рядом с данными.
- Скан локального файла и операции над ним — на клиенте.
- Соединение двух сторон происходит там, куда дешевле доставить меньший из промежуточных результатов.
Для пользователя это прозрачно. Вы пишете обычный запрос, не размечая операторы. То, что часть плана уехала в облако, видно в EXPLAIN: в плане появляются операторы, помеченные как удалённые.
ATTACH 'md:';
-- local_edits — локальный CSV; sales — большая таблица в облаке
EXPLAIN
SELECT s.region, sum(s.amount) AS total
FROM my_cloud_db.sales AS s
JOIN 'local_edits.csv' AS e ON s.region = e.region
GROUP BY s.region;
-- В плане видно разделение: скан и предагрегация sales помечены
-- как выполняемые на стороне MotherDuck, а скан local_edits.csv
-- и финальный JOIN — на стороне клиента. По сети между ними
-- двигается только агрегированный промежуточный результат.
Ключевой выигрыш: по сети едет не исходная 300-гигабайтная таблица, а её агрегат — возможно, несколько килобайт. Без dual execution выбор был бы между «залить локальное в облако» и «скачать облачное локально»; dual execution выбирает третий путь — двигать только то, что после фильтрации и агрегации стало маленьким.
Эвристика «оператор исполняется там, где его данные» объясняет, как писать запросы под dual execution. Фильтруйте и агрегируйте большую облачную таблицу до соединения с локальными данными: чем раньше в плане большой объём схлопывается в маленький, тем меньше едет по сети. Это та же дисциплина, что и pushdown, только граница проходит не «движок против файла», а «клиент против облака».
Когда MotherDuck оправдан, а когда хватает чистого DuckDB
MotherDuck решает конкретный набор задач, и за пределами этого набора чистого DuckDB достаточно.
| Задача | Чистый DuckDB | MotherDuck |
|---|---|---|
| Локальная аналитика, данные на одной машине | Полностью закрывает | Не нужен |
| Embedded-движок внутри приложения | Полностью закрывает | Не нужен |
| Общая база для команды | Нет встроенного шеринга | Облачное хранилище + шеринг |
| Запросы по расписанию без включённой машины | Нужен внешний шедулер | Встроенные scheduled-задачи |
| Compute мощнее ноутбука | Ограничен локальным железом | Серверные узлы облака |
| Запрос над «локальное + облачное» вместе | Только локальные источники | Dual execution |
Принцип простой: DuckDB — это движок, и для всего, что укладывается в «один процесс, одна машина, локальные данные», он самодостаточен и MIT-бесплатен. MotherDuck нужен, когда появляются именно облачные требования — совместный доступ, постоянное хранилище вне вашего диска, расписание, масштаб compute. Dual execution — это то, что делает переход в облако нерезким: вы не обязаны выбирать между «всё локально» и «всё в облаке», движок сам проводит границу по каждому запросу.
Попробуй сам
Для этого задания нужен бесплатный аккаунт MotherDuck (есть free tier). Установите свежий DuckDB CLI — поддержка md: встроена в движок.
Задания:
- Запустите
duckdbи выполнитеATTACH 'md:';— пройдите аутентификацию в браузере. После подключения выполнитеSHOW DATABASES;и найдите общий датасетsample_data. - Выполните агрегирующий запрос над таблицей из
sample_data(например, посчитайте строки и сгруппируйте по какой-нибудь колонке). Этот запрос целиком исполняется в облаке. - Создайте локально маленький CSV или таблицу в
memory-базе и напишите запрос, соединяющий её с облачной таблицей изsample_data. Запустите этот же запрос черезEXPLAINи найдите в плане операторы, помеченные как удалённые (исполняемые в облаке). - Поменяйте запрос так, чтобы фильтр по большой облачной таблице стоял до JOIN, и подумайте (по плану
EXPLAIN), как это влияет на объём данных, который должен пройти по сети между облаком и клиентом.