Duckdb internals: почему duckdb такой быстрый?

19.06.2026 · 5 мин

DuckDB — это аналитическая SQL-база данных, которая работает прямо внутри вашего процесса. Без сервера, без сети, без сериализации. Партизаны баз данных, грубо говоря.

Я недавно разбирался, как именно DuckDB умудряется быть быстрее целых кластеров на аналитических запросах. Ответ оказался не в одном трюке, а в наборе архитектурных решений, которые складываются в очень эффективную машину.

Давайте пройдёмся по ключевым механизмам.

Главный тезис: скорость — это сумма решений

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

Основные причины скорости:

Разберём каждый.

Почему отсутствие сервера — это уже оптимизация

Традиционные базы данных — это серверы. Вы подключаетесь по сети, отправляете SQL, получаете результат. Между вами и данными стоит протокол: ODBC, JDBC или какой-нибудь proprietary wire protocol.

На каждый результат приходится двойная работа: сначала база кодирует каждое значение в байты, потом клиент их декодирует обратно. На большом результате это может занимать больше времени, чем сам запрос.

ТРАДИЦИОННАЯ СУБД vs DUCKDB
─────────────────────────────
Традиционная СУБД:
  Python ──TCP──▶ Postgres ──encode──▶ Байты
  Python ◀──TCP──◀ Postgres ◀──decode──◀ Байты
  ────────────────────────────────────────
  Накладные расходы: сериализация + сеть

DuckDB:
  Python ──вызов──▶ libduckdb (тот же процесс)
  Python ◀──возврат◀ libduckdb
  ────────────────────────────────────────
  Накладные расходы: ноль
Сервер vs библиотека: разница в архитектуре

DuckDB — это библиотека. Вы загружаете её в свой процесс и вызываете функции напрямую. Никакого сетевого roundtrip, никакой сериализации.

Авторы статьи ссылаются на исследование 2017 года «Don’t Hold My Data Hostage», где измеряли накладные расходы протоколов ODBC и JDBC. Оказалось, что сам протокол передачи данных часто был медленнее, чем вычисление результата.

Колоночное хранение: почему это важно для аналитики

Аналитические запросы — это обычно сканы миллионов строк с фильтрацией, агрегацией и джойнами. Вам редко нужна одна строка по primary key.

Колоночное хранение означает, что данные лежат столбцами, а не строками. Вместо таблицы users как набора строк — три массива: id, name, email.

Преимущества:

СТРОЧНОЕ vs КОЛОНОЧНОЕ ХРАНЕНИЕ
───────────────────────────────
Строчное (традиционные СУБД):
  Строка 1: [id=1, name="Alice", email="a@"]
  Строка 2: [id=2, name="Bob", email="b@"]
  Строка 3: [id=3, name="Carol", email="c@"]
  ──────────────────────────────────────────
  Читаем столбец email → читаем всю строку

Колоночное (DuckDB):
  id    [1] [2] [3]
  name  ["Alice"] ["Bob"] ["Carol"]
  email ["a@"] ["b@"] ["c@"]
  ──────────────────────────────────────────
  Читаем столбец email → читаем только email
Колоночное хранение: читаем только нужное

Когда вы делаете SELECT email FROM users, строчная база данных читает всю строку, потом выбрасывает лишнее. DuckDB читает только массив email. На таблицах с десятками колонок это огромная разница.

Векторизованное выполнение: батчами, не построчно

Классические базы данных обрабатывают данные построчно: взяли строку, применили фильтр, записали результат. Цикл за циклом.

Векторизованное выполнение работает иначе: движок берёт блок строк, прогоняет через него операции и двигается дальше. Это позволяет:

DuckDB использует так называемый morsel-driven parallelism — данные разбиваются на кусочки, которые обрабатываются параллельно на всех ядрах. Каждый morsel — это несколько тысяч строк, которые помещаются в L2-кэш.

Replacement scan: zero-copy из Python

Вот фича, которая меня по-настоящему зацепила. Когда вы делаете con.sql(...), передавая pandas DataFrame, DuckDB не копирует данные в свою внутреннюю таблицу.

Вместо этого он делает replacement scan: подменяет ссылку на таблицу функцией, которая читает данные напрямую из DataFrame. Если NumPy говорит «вот буфер с миллионом int64», DuckDB может прочитать этот же буфер напрямую.

Это называется zero-copy: данные не копируются вообще. Один и тот же буфер в памяти используется и pandas, и DuckDB.

Arrow формат данных делает это ещё чище, потому что он уже спроектирован для shared memory между процессами.

Когда duckdb действительно выигрывает

DuckDB не заменит Snowflake или BigQuery на петабайтных данных. Но на конкретных сценариях он разносит их:

Компания MotherDuck делает из него облачное хранилище, Fivetran использует для мержинга, а Rill строит на нём BI-инструмент.

Выводы

DuckDB быстр не из-за одного хака. Каждый слой движка убран или оптимизирован:

Если вам нужна быстрая аналитика, попробуйте DuckDB. Это не займёт ни сервера, ни денег.

Ссылки

Дмитрий Полухин — продуктовый дизайнер. Пишу про разработку, AI и дизайн интерфейсов. Обо мне, контакты и профили.