Core и community-расширения: INSTALL, LOAD, autoloading
Ядро DuckDB намеренно небольшое: один бинарник без зависимостей, без сервера. Но при этом DuckDB умеет читать с S3, сканировать PostgreSQL, работать с Iceberg, делать пространственную аналитику и полнотекстовый поиск. Этот фокус — «маленькое ядро, огромные возможности» — держится на системе расширений. Расширение это подключаемый модуль, который добавляет в DuckDB новые функции, типы, сканеры или файловые системы, не раздувая ядро. Этот урок — про то, как расширения устроены, откуда берутся и как ими управлять. Без этого понимания все следующие уроки модуля (httpfs, сканеры баз, Iceberg, spatial) будут начинаться с непонятных команд.
Зачем DuckDB вообще модульность
У монолитного подхода — «всё в одном бинарнике» — две проблемы. Первая: размер. Драйвер S3, парсер Iceberg, библиотека пространственной геометрии — каждое тянет код и зависимости. Если зашить всё в ядро, бинарник раздуется, а большинству пользователей 90% этого кода не нужно. Вторая: цикл выпуска. Расширение можно обновлять и выпускать отдельно от ядра — исправление в драйвере S3 не ждёт следующего релиза DuckDB.
Расширения решают обе проблемы. Ядро остаётся компактным, а возможности подключаются по требованию. Технически расширение — это динамически загружаемый модуль (.duckdb_extension), который при загрузке регистрирует в работающем экземпляре новые объекты: скалярные и table functions, типы, file systems, оптимизационные правила.
Core против community-расширений
Расширения делятся на две категории по происхождению и уровню доверия.
Core-расширения разрабатываются и сопровождаются командой DuckDB (DuckDB Labs) или в тесной координации с ней. Они проходят тестирование вместе с релизами DuckDB, подписаны, и им можно доверять как части продукта. В семейство core входят: httpfs (удалённые файловые системы — S3, GCS, Azure, HTTP), aws и azure (интеграция с облаками), iceberg, delta, ducklake (lakehouse-форматы), postgres, mysql, sqlite (сканеры баз данных), json, excel, parquet (форматы; parquet встроен в ядро), spatial (геоаналитика), fts (полнотекстовый поиск), vss (поиск по векторному сходству), icu (поддержка часовых поясов и Unicode-collation), tpch и tpcds (генераторы бенчмарк-данных).
Community-расширения пишутся сторонними разработчиками и публикуются через отдельный community-репозиторий. Они проходят сборку через инфраструктуру DuckDB, но их код и поддержка — на стороне авторов, не DuckDB Labs. Это пространство для нишевых интеграций: специфичные форматы, экзотические функции, экспериментальные идеи. Многие community-расширения отличного качества, но уровень гарантий ниже, чем у core.
| Аспект | Core-расширения | Community-расширения |
|---|---|---|
| Кто разрабатывает | DuckDB Labs | Сторонние авторы |
| Репозиторий | core-репозиторий | community-репозиторий |
| Тестирование с релизами | Да | Сборка через инфраструктуру DuckDB |
| Подпись | Да | Да (через инфраструктуру) |
| Autoloading | Возможен | Нет — только явный INSTALL |
| Уровень доверия | Как часть продукта | На усмотрение пользователя |
Граница «core против community» подвижна. Удачное и востребованное community-расширение может со временем перейти в core. ducklake — реализация lakehouse-формата DuckLake — пример быстро выросшей до core-уровня вещи: к 2026 году это одно из самых скачиваемых core-расширений. Так что состав core со временем меняется.
INSTALL и LOAD: два разных шага
Управление расширениями — это две отдельные команды, и важно не путать, что делает каждая.
INSTALL extension_name — скачивает расширение из репозитория и сохраняет его на локальный диск, в каталог расширений. Делается один раз: после установки файл лежит локально и при следующих запусках DuckDB заново скачивать его не надо. Это операция уровня машины.
LOAD extension_name — загружает уже установленное расширение в текущий работающий экземпляр DuckDB: подгружает динамический модуль и регистрирует его функции и типы. Это операция уровня сессии: загрузку нужно повторять в каждом новом подключении (каждый новый процесс DuckDB стартует с чистым набором загруженных расширений).
-- Скачать расширение на диск (один раз на машину)
INSTALL spatial;
-- Загрузить его в текущую сессию (каждый раз при новом подключении)
LOAD spatial;
-- Теперь функции расширения доступны
SELECT ST_Point(13.4, 52.5) AS berlin;
Посмотреть состояние всех расширений можно через служебную функцию:
SELECT extension_name, installed, loaded
FROM duckdb_extensions()
WHERE extension_name IN ('spatial', 'httpfs', 'json');
┌────────────────┬───────────┬─────────┐
│ extension_name │ installed │ loaded │
│ varchar │ boolean │ boolean │
├────────────────┼───────────┼─────────┤
│ httpfs │ true │ false │
│ json │ true │ true │
│ spatial │ true │ true │
└────────────────┴───────────┴─────────┘
Здесь видно различие: installed — расширение скачано на диск; loaded — оно подгружено в эту конкретную сессию.
Autoloading: когда команды не нужны вообще
Большую часть времени вы не пишете ни INSTALL, ни LOAD. Запрос SELECT * FROM 's3://bucket/file.parquet' или SELECT * FROM read_json('data.json') просто работает, хотя ни httpfs, ни json вы руками не загружали. Это autoloading — автоматическая загрузка расширений.
Механизм такой: когда DuckDB при разборе запроса встречает функцию, тип или путь, который обслуживается известным core-расширением, и это расширение ещё не загружено, DuckDB загружает его сам. Если расширение ещё и не установлено — DuckDB сначала скачает его, потом загрузит. Всё прозрачно: с точки зрения пользователя запрос просто выполнился.
Autoloading работает только для core-расширений. Это сознательное решение про безопасность: автоматически подтягивать и запускать сторонний код было бы рискованно, поэтому community-расширения всегда требуют явного INSTALL. Управляют поведением два параметра: autoinstall_known_extensions и autoload_known_extensions (оба по умолчанию включены). В изолированных окружениях без доступа к сети autoinstall можно выключить.
Из autoloading есть важное исключение, и его легко забыть: расширение spatial НЕ autoloadable. Хотя spatial — полноценное core-расширение, его нельзя подтянуть автоматически: первое же обращение к пространственной функции вроде ST_Point без предварительной загрузки даст ошибку. Для spatial всегда нужны явные INSTALL spatial; LOAD spatial;. Об этом отдельно — в уроке про spatial.
Откуда расширения берутся: репозитории
INSTALL extension_name скачивает расширение из репозитория расширений по HTTP. По умолчанию это официальный core-репозиторий DuckDB. Community-расширения лежат в отдельном community-репозитории, и DuckDB знает про оба.
Расширения собираются под конкретную версию DuckDB и платформу (комбинация ОС и архитектуры процессора — например linux_amd64, osx_arm64). Поэтому при обновлении DuckDB установленные расширения, как правило, нужно переустановить под новую версию — старый бинарник расширения собран под старый ABI ядра. Команда UPDATE EXTENSIONS обновляет установленные расширения до версий, совместимых с текущим DuckDB.
-- Установить из явно указанного репозитория
INSTALL extension_name FROM community;
-- Обновить все установленные расширения
UPDATE EXTENSIONS;
Расширения подписаны: DuckDB проверяет подпись при загрузке. Загрузка неподписанного или собранного вами вручную расширения требует флага allow_unsigned_extensions — это пригодится при разработке собственных расширений (последний урок модуля), но в обычной работе подпись лучше не отключать.
Попробуй сам
Поработайте с системой расширений на чистом экземпляре DuckDB.
- Выполните
SELECT extension_name, installed, loaded, description FROM duckdb_extensions() ORDER BY extension_name. Изучите список: какие расширения уже установлены, какие загружены в свежей сессии, что каждое делает. - Выполните
INSTALL fts;затемLOAD fts;. Снова посмотритеduckdb_extensions()дляfts— проследите, как менялись поляinstalledиloaded. - Запустите запрос к JSON-файлу (
SELECT * FROM read_json('any.json')) в сессии, где json вы не загружали. Затем проверьтеduckdb_extensions()для json — расширение сталоloadedсамо. Это autoloading в действии. - Попробуйте
SELECT ST_Point(0, 0)БЕЗ предварительной загрузки spatial. Получите ошибку. Затем выполнитеINSTALL spatial; LOAD spatial;и повторите. Объясните себе, почему здесь autoloading не сработал, а для json сработал.