Learning Platform
Глоссарий Troubleshooting
Урок 01.01 · 20 мин
Средний
duckdbolapembedded-databasesqlite

Что такое DuckDB и почему «SQLite для аналитики»

Когда инженеру данных нужно посчитать агрегаты по сотне миллионов строк, у него обычно два инструмента: либо тяжёлый распределённый движок (Spark, кластер с координатором и воркерами), либо хрупкий скрипт на pandas, который падает с MemoryError на середине датасета. Между этими крайностями долго ничего не было: ничего, что одновременно понимало бы полноценный SQL, считало бы быстрее pandas, не требовало бы сервера и помещалось в один бинарник. Это была реальная, ощутимая пустота в инструментарии инженера данных, и закрыть её было нечем — пока не появился DuckDB.

DuckDB закрывает именно эту нишу. Это in-process аналитическая СУБД — она работает прямо внутри вашего процесса (Python-интерпретатора, R-сессии, CLI), без отдельного сервера и без сетевого соединения. Версия на момент написания курса — DuckDB 1.5.2 (последняя стабильная, вышла 13 апреля 2026), плюс активная LTS-линия 1.4.x «Andium». DuckDB 2.0 запланирован на сентябрь 2026.

В этом уроке мы разберём, что стоит за фразой «SQLite для аналитики» и почему это точное, а не маркетинговое сравнение. Это первый урок курса, и его задача — дать общую картину: что такое DuckDB, для чего он создан и где проходят его границы. Детали — диалект, типы, внутреннее устройство — будут в следующих модулях; здесь важно увидеть инструмент целиком.


Что значит «in-process» и почему это важно

Большинство СУБД, с которыми вы сталкивались — PostgreSQL, MySQL, ClickHouse — устроены по клиент-серверной модели. Есть отдельный процесс-демон, который слушает порт. Ваше приложение подключается к нему по сети (даже если «сеть» — это localhost), отправляет SQL-запрос, получает результат обратно. Это удобно для многопользовательского доступа, но у этого есть цена: сериализация запроса, сетевой round-trip, десериализация результата.

DuckDB устроен иначе. Это библиотека, которую вы линкуете в свой процесс — точно так же, как линкуете numpy или requests. Нет демона. Нет порта. Нет сетевого протокола. Когда вы вызываете duckdb.sql("SELECT ...") из Python, движок СУБД исполняется в том же адресном пространстве, что и ваш Python-код.

Клиент-сервер против in-process
ПриложениеВаш Python/Java/Go процесс
сеть / сокет
СУБД-серверОтдельный процесс-демон PostgreSQL/MySQL: слушает порт, имеет собственную память, требует запуска и администрирования
Приложение + DuckDBDuckDB слинкован в тот же процесс: вызов функции вместо сетевого запроса, общая память, нулевая сериализация
вызов функции
Та же памятьDuckDB читает и пишет данные в том же адресном пространстве — DataFrame не копируется при передаче в движок

У этого три прямых следствия. Первое: нулевая стоимость передачи данных. Если у вас в Python есть pandas DataFrame, DuckDB может прочитать его прямо из памяти, без копирования и сериализации — потому что находится в той же памяти. Второе: нечего администрировать. Нет процесса, который надо запускать, мониторить, перезапускать. Третье: простая модель развёртывания. Установка DuckDB — это pip install duckdb, и всё. Никаких docker-compose, никаких портов, никаких пользователей и паролей.

Эти три следствия — не разные удобства, а грани одного факта: у DuckDB нет процесса, отдельного от вашего приложения. Раз нет отдельного процесса — нечему изолировать от вас данные (отсюда нулевая стоимость передачи), нечего держать запущенным и мониторить (отсюда отсутствие администрирования), нечего разворачивать как сервис (отсюда простота установки). Один архитектурный выбор — in-process — определяет сразу весь характер инструмента. Курс будет возвращаться к этой мысли не раз: очень многое в DuckDB, и хорошее, и его ограничения, вытекает именно из решения быть встраиваемым, а не серверным.


SQLite — но для другого класса задач

Аналогия с SQLite не случайна. SQLite — самая распространённая СУБД в мире: она встроена в каждый телефон, браузер, множество приложений. Её ключевая идея — встраиваемость: база данных как библиотека, файл базы — обычный файл на диске, никакого сервера.

DuckDB берёт ровно эту идею встраиваемости, но применяет её к другому классу нагрузок. SQLite спроектирован для OLTP (Online Transaction Processing): много мелких операций — вставить строку, прочитать одну запись по ключу, обновить поле. Так работает приложение: пользователь нажал кнопку — одна короткая транзакция.

DuckDB спроектирован для OLAP (Online Analytical Processing): мало запросов, но каждый «широкий» — просканировать миллионы строк, посчитать SUM, GROUP BY, соединить несколько таблиц. Так работает аналитика: посчитать выручку за квартал по сегментам.

СвойствоSQLiteDuckDB
Класс нагрузкиOLTP (транзакции)OLAP (аналитика)
Хранение данныхПострочное (row-store)Поколоночное (columnar)
Модель встраиванияIn-process, single binaryIn-process, single binary
Типичный запросSELECT * WHERE id = ?SELECT region, SUM(amount) GROUP BY region
Движок исполненияПострочный интерпретаторВекторизованный
ЛицензияPublic DomainMIT

Главное техническое отличие — способ хранения данных на диске. Это решающий момент, поэтому разберём его подробнее.

Декларативность SQL: «что», а не «как»

Прежде чем перейти к раскладке данных, стоит чуть подробнее объяснить, почему OLTP и OLAP — это действительно два разных мира, а не два режима одного. OLTP-нагрузка обслуживает работу приложения в реальном времени: пользователь совершает действие, и система должна за миллисекунды его обработать. Здесь важны короткие операции над отдельными записями и надёжность каждой записи. OLAP-нагрузка обслуживает принятие решений: аналитик или отчёт задаёт вопрос вроде «как менялась выручка по кварталам», и система перемалывает большой массив накопленных данных, чтобы дать ответ. Здесь важна пропускная способность на больших объёмах, а не скорость отдельной мелкой операции. Эти две задачи предъявляют к движку противоположные требования, и потому СУБД исторически разделились на два лагеря. SQLite — выдающийся представитель OLTP-лагеря среди встраиваемых СУБД. До DuckDB во встраиваемом OLAP-лагере фактически зияла пустота — её DuckDB и заполнил.


Почему columnar-хранение бьёт row-store на аналитике

Представьте таблицу заказов: миллион строк, 20 колонок (order_id, customer_id, amount, region, created_at, …). Её надо как-то разложить в линейную память диска. Есть два способа.

Row-store (как SQLite, PostgreSQL): данные хранятся построчно. Сначала все 20 полей первой строки подряд, затем все 20 полей второй строки, и так далее. Это идеально, когда вам нужна вся строка целиком — типичная OLTP-операция.

Columnar-store (как DuckDB, ClickHouse): данные хранятся поколоночно. Сначала все миллион значений колонки order_id подряд, затем все значения customer_id, затем amount. Это идеально, когда вам нужно несколько колонок по всем строкам — типичная OLAP-операция.

Раскладка таблицы в памяти: row против columnar
Row-storeСтроки лежат целиком: запрос только по amount всё равно тянет с диска все 20 колонок каждой строки
Columnar-storeКолонки лежат отдельно: запрос по amount читает только блок amount, остальные 19 колонок диск вообще не трогает

Теперь запрос SELECT region, SUM(amount) FROM orders GROUP BY region. Ему нужны ровно две колонки из двадцати.

В row-store движок вынужден прочитать с диска все строки целиком — потому что значения amount физически перемежаются с 19 ненужными полями. Чтобы добраться до миллиона значений amount, диск прочитает в 10 раз больше данных, чем нужно.

В columnar-store движок читает только блок region и блок amount. Остальные 18 колонок на диске не трогаются вообще. Это даёт двукратную, а на широких таблицах десятикратную экономию ввода-вывода — даже без учёта сжатия.

И это ещё не всё. Когда колонка лежит как непрерывный массив однотипных значений, к ней применимы две вещи, недоступные для row-store: эффективное сжатие (соседние значения одной колонки похожи между собой — лучше сжимаются) и векторизованное исполнение (процессор обрабатывает массив значений пачками, используя SIMD-инструкции). Обе эти темы мы разберём «до железа» в отдельных модулях курса.

Стоит пояснить, почему именно однотипный непрерывный массив так хорош для процессора.

Row vs Columnar: сравнение форматов хранения

ClickHouse: смена ментальных моделей для OLAP Современный процессор быстрее всего работает, когда выполняет одну и ту же операцию над потоком одинаковых данных: он может предсказать, что будет дальше, заранее подгрузить данные в кэш, а инструкции SIMD позволяют одной командой обработать сразу несколько значений. Колонка целых чисел — идеальная пища для такого режима: миллион значений одного типа, лежащих подряд. Строка же из 20 разнотипных полей — наоборот, «рваные» данные, на которых процессор постоянно переключается. Поэтому columnar-раскладка — это не только про экономию ввода-вывода, но и про то, чтобы дать процессору работать в его самом быстром режиме. Это две независимые причины, по которым columnar выигрывает на аналитике, и обе вытекают из одной идеи: хранить вместе то, что вместе обрабатывается.

NOTE

DuckDB сжимает данные только для persistent-баз (файл на диске). In-memory база данных хранит колонки несжатыми — потому что цель in-memory режима скорость, а не экономия места. Это важная деталь, к которой мы вернёмся в модуле про storage-формат.


Что DuckDB НЕ есть

Чтобы аналогия с SQLite не сбивала с толку, зафиксируем границы. Знать, чем инструмент не является, не менее важно, чем знать его сильные стороны: именно непонимание границ ведёт к неудачным архитектурным решениям. Разберём четыре частых заблуждения.

DuckDB не сервер. Нельзя поднять его как демон и подключать к нему сотню клиентов по сети. Один процесс — одна база. Если нужен многопользовательский сетевой доступ к одним и тем же данным, DuckDB не ваш инструмент (для облачного сценария есть MotherDuck, но это отдельный managed-сервис).

DuckDB не замена PostgreSQL для приложения. Транзакционная нагрузка веб-приложения — тысячи мелких конкурентных вставок и обновлений в секунду — это анти-паттерн для DuckDB. У него модель конкурентности «один писатель, много читателей» в рамках одного процесса. Для OLTP берите PostgreSQL или SQLite.

DuckDB не «просто быстрый pandas». Это полноценная СУБД: с ACID-транзакциями, реальным оптимизатором запросов, persistent-хранилищем и способностью обрабатывать данные больше объёма RAM (спиллинг на диск). pandas всего этого не умеет.

DuckDB не ограничен размером оперативной памяти. Это частое заблуждение. DuckDB умеет out-of-core исполнение: если датасет не помещается в RAM, движок выгружает промежуточные результаты на диск и доводит запрос до конца. Подробно — в модуле про larger-than-memory.


Где DuckDB особенно уместен

Зная границы, посмотрим на сильную сторону — на задачи, под которые DuckDB создан и где он один из лучших инструментов.

Разведочный анализ данных. У вас есть датасет — файл или несколько файлов — и нужно его понять: посчитать распределения, агрегаты, найти аномалии. DuckDB позволяет делать это интерактивно, полноценным SQL, быстро, без поднятия инфраструктуры. Открыли — и сразу работаете с данными.

Трансформация данных в пайплайне. В подходе ELT (Extract-Load-Transform) данные сначала загружают, а потом трансформируют. DuckDB — отличный движок для шага трансформации на одной машине: читает сырые данные, чистит, агрегирует, моделирует, отдаёт результат. Аналитический SQL для этого — естественный язык.

Аналитика внутри приложения. Приложению нужно посчитать отчёт по локальным данным — DuckDB встраивается в него как библиотека и делает это быстро, не требуя отдельной СУБД-инфраструктуры.

Замена тяжёлым скриптам обработки данных. Скрипт, который медленно перемалывает данные построчно или упирается в память, часто можно заменить на несколько SQL-запросов DuckDB — короче, быстрее и без риска MemoryError.

Общее у этих сценариев — аналитическая нагрузка, одна машина, один процесс. Это и есть профиль DuckDB. Курс дальше разбирает каждый такой сценарий подробно; пока важно увидеть очертания: DuckDB силён там, где нужен быстрый аналитический SQL без тяжёлой инфраструктуры.


Попробуй сам

Лучший способ почувствовать, что такое DuckDB, — запустить его прямо сейчас. Установите DuckDB и убедитесь, что «in-process» — это буквально не фигура речи. Выполните в терминале:

pip install duckdb
python3 -c "import duckdb; print(duckdb.sql('SELECT 42 AS answer'))"

Вывод будет примерно таким:

┌────────┐
│ answer │
│ int32  │
├────────┤
│     42 │
└────────┘

Обратите внимание: вы не запускали никакого сервера, не открывали порт, не указывали host. Импорт библиотеки — и SQL уже работает. Теперь сравните: попробуйте вспомнить, сколько шагов нужно, чтобы получить такой же результат из PostgreSQL (установить сервер, запустить демон, создать пользователя, подключиться). Эта разница в количестве шагов и есть практический смысл слов «in-process» и «single binary».

Сделав эту проверку, зафиксируйте для себя главный вывод урока одним предложением: DuckDB — это встраиваемая аналитическая СУБД, аналог SQLite для OLAP-нагрузок, и почти все его свойства — и сильные стороны, и ограничения — вытекают из двух решений: быть in-process и хранить данные поколоночно. С этой опорной мыслью вам будет легче воспринимать остальной курс.

Дальше, в следующем уроке, мы пройдём карту всего курса — от SQL-диалекта до байтов storage-формата — чтобы вы видели весь маршрут заранее.


Как создавался курс

Курс создан при участии Claude (Anthropic) как соавтора: ИИ помогал писать материалы, структурировать темы, генерировать примеры кода и диаграммы. Каждая глава проходила ручную сверку с первоисточниками — спецификациями, документацией, исходным кодом рассматриваемых систем — но гарантировать 100% точность невозможно.

Если вы заметили неточность, опечатку или хотите предложить улучшение — напишите в Telegram-группу курса. Это самый ценный вклад в курс, который вы можете сделать.


Углублённое изучение с Claude

Курс рассчитан на самостоятельное изучение, но любая теория быстрее ложится, если задавать вопросы. Рекомендую держать рядом браузерное расширение Claude (claude.com/download) — оно работает с контентом открытой страницы: выделяете кусок урока и спрашиваете напрямую.

Сценарии, которые особенно хорошо работают для углублённого погружения:

  • «Объясни проще» / «дай ещё один пример» — когда формулировка из урока не дошла с первого раза.
  • «Покажи, как это устроено на уровне кода / железа» — когда хочется спуститься на слой ниже того, что даёт урок.
  • «Как это связано с [другая тема курса]» — когда нужно увязать концепцию с тем, что было раньше.
  • «У меня в проекте стек X — как применить?» — когда хочется примерить материал на свой реальный кейс.

Это не замена курсу, а способ ускорить интеграцию материала в вашу картину мира. Если что-то из ответов Claude расходится с уроком — присылайте в Telegram-группу, курс будет уточнён.


Нашли ошибку?

Если заметили неточность, опечатку или хотите предложить улучшение:

Telegram-группа курса
Обсуждение, вопросы, предложения

Telegram-канал

Подписывайтесь, чтобы узнавать об обновлениях и новых курсах:

@levoely_channel
Новости, обновления, новые курсы

Проверка знанийKnowledge check
Почему columnar-хранение даёт DuckDB преимущество на аналитических запросах, и почему то же самое хранение было бы плохим выбором для OLTP-нагрузки SQLite?
ОтветAnswer
Аналитический запрос обычно читает несколько колонок по всем строкам (например, region и amount из таблицы с 20 колонками). В columnar-хранении значения одной колонки лежат непрерывным массивом, поэтому движок читает с диска только нужные колонки, а остальные не трогает вообще — это даёт многократную экономию ввода-вывода. Кроме того, непрерывный однотипный массив лучше сжимается и обрабатывается векторизованно через SIMD. Для OLTP-нагрузки SQLite та же раскладка была бы вредной: транзакционные операции работают со строкой целиком (вставить запись, прочитать одну строку по ключу, обновить поле). В columnar-хранении поля одной строки физически разбросаны по разным колоночным блокам, поэтому собрать или вставить одну строку означало бы трогать все колоночные сегменты. Поэтому SQLite использует row-store, оптимальный для строко-ориентированных транзакций, а DuckDB — columnar-store, оптимальный для колоночной аналитики.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. Что означает характеристика DuckDB как «in-process» СУБД?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 3