Перейти к содержимому
TelegramGitHub

DuckDB: Up and Running, глава 9: DuckDB в облаке с MotherDuck

Главная мысль: MotherDuck — это DuckDB как облачный сервис. Вы загружаете данные один раз, делитесь ими по ссылке и запускаете запросы без своего сервера. Особенность — hybrid-запрос: один запрос читает и локальные файлы, и таблицы в облаке.

  • Serverless-платформа аналитики на базе DuckDB. Без установки и настройки машины.
  • Читает Parquet, CSV, JSON, Iceberg и Delta Lake.
  • Каждому пользователю даётся свой изолированный compute. Он масштабируется независимо.
  • Функция Dual Execution: часть запроса идёт локально, часть в облаке.
  • Инфраструктура работает в AWS. Сервисы идут в контейнерах под Kubernetes.
ПланЦена в книгеЧто входит
Trial30 дней бесплатноВсе возможности
Free$0 в месяц на организацию5 участников, 10 CU-часов, 10 GB хранилища
Standard$25 в месяц на организациюБезлимит участников, 100 CU-часов, 100 GB. Можно докупать

CU — compute unit, единица вычислений. Цены и лимиты быстро меняются. Проверьте их на сайте перед выбором. Это данные на момент выхода книги (декабрь 2024).

Вход через Google, GitHub или email с паролем. Веб-интерфейс похож на Jupyter: слева панели, справа ноутбук с SQL-ячейками.

Слева два раздела:

  • Notebooks — ваши ноутбуки.
  • Attached databases — подключённые базы.

По умолчанию подключены две базы:

БазаЧто этоПрава
my_dbВаша база для своих данныхЧтение и запись
sample_dataУчебные таблицыТолько чтение (shared database)

Порядок имён: база.схема.таблица. Пример: my_db.main.airlines.

  • В базе есть схемы. Схема по умолчанию — main.
  • Схема группирует связанные таблицы.
  • Загрузка данных: кнопка Add Data, затем в ячейке указать полное имя таблицы: CREATE OR REPLACE TABLE my_db.main.airlines AS SELECT * FROM read_csv_auto(['airlines.csv']).
  • CREATE SCHEMA my_db.titanic создаёт схему.
  • DROP SCHEMA titanic CASCADE удаляет схему вместе с таблицами. Без CASCADE непустую схему не удалить.
CREATE DATABASE flights_db;
USE flights_db;
DETACH flights_db;
  • Новую базу можно создать только командой SQL. Через интерфейс пока нельзя.
  • USE выбирает базу по умолчанию для следующих запросов.
  • DETACH отключает базу и освобождает ресурсы. Данные остаются. Потом её можно подключить снова.

Share даёт другим людям доступ к вашей базе только для чтения. Данные не копируются.

ШагКоманда или действие
Создать shareВ меню базы выбрать Share, задать имя и доступ
Уровни доступаAnyone in my organization или Anyone with the share link
Подключить чужой shareATTACH 'md:_share/<имя>/<id>' AS my_alias;
Показать свои sharesLIST SHARES
Передать новые измененияUPDATE SHARE <имя>;
ОстановитьDrop в меню share
  • Share — это снимок базы. Получатели видят изменения только после UPDATE SHARE.
  • Получатель задаёт своё имя базы через AS. Иначе имя может совпасть с его my_db.
  • Ссылку с доступом «anyone with the link» нельзя выкладывать публично, если данные закрытые.
  • Результат запроса показывается вместе со статистикой по колонкам справа.
  • Для текста видно частоты значений. Для чисел — гистограмма и квантили: min, медиана, mean, стандартное отклонение.
  • Это быстрая EDA без отдельных запросов GROUP BY.

MotherDuck встроил LLM в SQL. Это функции и pragma.

ЧтоЧто делает
prompt_sql()Пишет SQL по вопросу на английском
prompt_queryСразу даёт ответ на вопрос о данных
prompt_fixup()Исправляет запрос
prompt_fix_line()Исправляет запрос построчно
prompt_schema()Описывает содержимое базы
prompt_explain()Объясняет, что делает запрос

Пример из книги (не запускайте без аккаунта):

USE my_db;
CALL prompt_sql('How many passengers travelled alone and survived?');
PRAGMA prompt_query('How many airlines are there?');

prompt_sql возвращает текст запроса. Вы читаете его и запускаете сами. prompt_query сразу отдаёт результат.

Проверяйте SQL от LLM перед запуском. Модель может понять вопрос неверно. Например, «один пассажир» она может записать как условие на несколько колонок.

Нужен DuckDB версии 1.0.0 или выше.

duckdb
ATTACH 'md:';
  • Команда выдаёт код. Откройте ссылку, проверьте, что код тот же, подтвердите вход и дайте доступ.
  • После входа токен сохраняется. PRAGMA PRINT_MD_TOKEN; показывает его. Его можно положить в переменную окружения, чтобы не входить снова.
  • Токен — это пароль. Не публикуйте его и не коммитьте.
  • SHOW databases;, SELECT current_database();, SELECT current_schema(); показывают, где вы.
  • Дальше всё работает как локально: USE my_db.titanic;, CREATE DATABASE, INSERT.

Один запрос соединяет локальный файл и облачную таблицу.

SELECT f.AIRLINE, f.FLIGHT_NUMBER, a.AIRLINE AS airline_name
FROM (SELECT AIRLINE, FLIGHT_NUMBER FROM './flights.csv' LIMIT 10) AS f
JOIN my_db.main.airlines AS a
ON f.AIRLINE = a.IATA_CODE;
  • Большой файл остаётся у вас. Небольшой справочник лежит в облаке.
  • Обработка делится между локальной машиной и облаком (Dual Execution). Передаётся только нужное.
ТерминЗначение
MotherDuckОблачный сервис на DuckDB
ServerlessНет своего сервера. Платите за использование
Compute unit (CU)Единица вычислений в тарифе
ShareДоступ к снимку базы только для чтения
ATTACH / DETACHПодключить / отключить базу
SchemaГруппа таблиц внутри базы
Dual ExecutionЗапрос идёт частично локально, частично в облаке
Hybrid queryЗапрос по локальным и облачным данным
  • Для небольшой команды MotherDuck — простое хранилище без администрирования. Для больших нагрузок проверьте тарифы и лимиты.
  • Shares удобны для общих справочников и учебных данных. Не нужно копировать и рассылать файлы.
  • Работайте в двух средах: локально для разработки, в облаке для общих данных. Hybrid-запрос соединяет их.
  • LLM-функции ускоряют черновики SQL, но результат нужно проверять. В dbt такой SQL попадает в модели только после ревью и тестов.
  • Токены MotherDuck храните как секреты, не в репозитории.

Запустите duckdb в терминале. Блоки идут по порядку. Аккаунт не нужен. Вторая база в памяти играет роль облака: у неё те же команды ATTACH, USE, CREATE SCHEMA. Для настоящего облака адрес будет md: вместо :memory:.

-- вторая база. В MotherDuck было бы ATTACH 'md:my_db'
ATTACH ':memory:' AS cloud_db;
CREATE SCHEMA cloud_db.ref;
CREATE TABLE cloud_db.ref.airlines AS
SELECT * FROM (VALUES
('AA', 'Air Alpha'),
('BB', 'Blue Bird'),
('CC', 'Cloud Carrier')
) t(iata_code, airline_name);
-- «локальные» рейсы в основной базе
CREATE TABLE flights AS
SELECT
['AA', 'BB', 'CC', 'DD'][1 + i % 4] AS airline,
1000 + i AS flight_number
FROM range(0, 12) t(i);
SHOW DATABASES;
SELECT current_database() AS db, current_schema() AS schema_name;
SELECT count(*) AS n FROM cloud_db.ref.airlines; -- ожидаем 3
SELECT f.airline, a.airline_name, count(*) AS flights
FROM flights AS f
LEFT JOIN cloud_db.ref.airlines AS a ON f.airline = a.iata_code
GROUP BY f.airline, a.airline_name
ORDER BY f.airline;

Проверка: для авиакомпании DD имени нет. Это NULL, потому что в справочнике её нет.

  1. Выберите cloud_db.ref как схему по умолчанию командой USE и прочитайте airlines без полного имени.
  2. Создайте базу scratch, таблицу в ней, потом отключите базу командой DETACH.
  3. Найдите рейсы, у которых нет авиакомпании в справочнике.
  4. Удалите схему ref вместе с таблицами.
Решение
-- 1. короткое имя после USE
USE cloud_db.ref;
SELECT count(*) AS n FROM airlines;
USE memory.main;
-- 2. своя база и DETACH
ATTACH ':memory:' AS scratch;
CREATE TABLE scratch.main.t AS SELECT 1 AS id;
DETACH scratch;
-- 3. рейсы без записи в справочнике (антиджойн)
SELECT f.*
FROM flights AS f
LEFT JOIN cloud_db.ref.airlines AS a ON f.airline = a.iata_code
WHERE a.iata_code IS NULL;
-- 4. схема удаляется только с CASCADE, если в ней есть таблицы
DROP SCHEMA cloud_db.ref CASCADE;
SELECT count(*) AS schemas_left FROM information_schema.schemata WHERE catalog_name = 'cloud_db' AND schema_name = 'ref';

Пункт 3 вернул 3 рейса компании DD. Последний запрос вернул 0: схемы больше нет.

  1. Чем MotherDuck отличается от локального DuckDB? Что он добавляет?
  2. Что такое share и почему получатель не может менять данные?
  3. Как получить свежие изменения в share после правки базы?
  4. Что такое hybrid-запрос? Приведите пример, где он удобен.

Предыдущая: Глава 8. Удалённые данные. Следующей главы нет. Вернитесь к обзору книги.