Привет, Хабр! Если вы хоть раз пытались выгрузить из базы данных несколько гигабайт данных в pandas
DataFrame, то вам знакома эта боль. Вы пишете простой SELECT
, запускаете скрипт и... уходите пить кофе. А потом ещё раз. Почему так медленно? Ведь и база быстрая, и сетка не загружена, и ваш Python-скрипт крутится на мощной машине.
Проблема кроется в невидимом, но коварном враге — старых и проверенных, как дедушкин паяльник, протоколах вроде ODBC и JDBC. Они были созданы для мира транзакционных, построчных баз данных и совершенно не готовы к современным аналитическим нагрузкам.
Давайте разберёмся, почему они так тормозят и какой стек технологий приходит им на смену, обещая скорости, о которых мы раньше только мечтали.
В основу легла статья Dipankar Mazumdar.
Почему ODBC/JDBC — это бутылочное горлышко?
Представьте, что вам нужно перевезти груз из точки А в точку Б. ODBC/JDBC — это как если бы вы каждую вещь из грузовика тщательно упаковывали в отдельную коробочку (сериализация на стороне сервера), перевозили, а потом на месте каждую коробочку так же тщательно распаковывали (десериализация на стороне клиента). Этот процесс упаковки/распаковки отъедает львиную долю процессорного времени и становится главным узким местом.
Построчная передача: Эти протоколы передают данные строка за строкой. Для аналитики, где мы обычно работаем с целыми колонками, это крайне неэффективно.
Текстовый или проприетарный бинарный формат: Данные преобразуются в некий промежуточный формат, который потом нужно парсить на клиенте.
INTEGER
превращается в строку "123", потом обратно вINTEGER
. Это лишняя работа.Безумная сериализация/десериализация (SerDe): Это главный убийца производительности. CPU на обеих сторонах тратят циклы не на вычисления, а на бессмысленную перепаковку данных из одного представления в другое.
В итоге, пока данные доедут от базы до вашего pandas
или Polars
, они пройдут через несколько кругов ада преобразований.
Шаг 1: Общий язык — Apache Arrow
Прежде чем говорить о транспорте, нужен стандартный "контейнер" для данных. И этот контейнер — Apache Arrow.
Если вы ещё не слышали об Arrow, то вот краткая суть: это стандарт для представления табличных данных в памяти (in-memory) в колоночном формате.

Ключевые фишки Arrow:
Колоночный формат: Идеально для аналитики. Нужно посчитать среднее по одной колонке? Читаем только её, а не всю таблицу.
Zero-copy: Данные в памяти лежат в таком формате, что их можно передавать между процессами (например, из Java-приложения в Python-скрипт) без дорогостоящего копирования и SerDe.
Языковая независимость: Есть реализации для Python, Java, C++, Rust и т.д. Все они понимают один и тот же формат данных.
Arrow решил проблему представления данных. Но как их эффективно передавать по сети?
Шаг 2: Транспорт — Apache Arrow Flight
И вот тут на сцену выходит Arrow Flight. Если Arrow — это стандартный ISO-контейнер для данных, то Flight — это высокоскоростной поезд-маглев, созданный специально для перевозки этих контейнеров.
Arrow Flight — это фреймворк для высокопроизводительной передачи данных на основе gRPC.
Что под капотом?
Протокол поверх gRPC/HTTP2: Это даёт нам все плюшки современного сетевого взаимодействия — мультиплексирование, потоковую передачу и т.д.
Никакой SerDe: Сервер отдаёт данные сразу в формате Arrow. Клиент их получает в том же виде. Никакой перепаковки. Данные как лежали в памяти сервера, так и "телепортируются" в память клиента.
Параллельная передача: Flight позволяет передавать данные в несколько параллельных потоков, полностью утилизируя сетевой канал и многоядерные процессоры.
В итоге мы получаем ускорение передачи данных в 10, 50, а иногда и в 100+ раз по сравнению с ODBC/JDBC. Кофе выпить точно не успеете.
Шаг 3: Язык запросов — Flight SQL
Окей, у нас есть быстрый транспорт. Но как сказать базе данных, какие именно данные мы хотим получить? Просто передавать сырые байты — это не очень удобно. Нам нужен стандартный способ отправлять SQL-запросы.
Arrow Flight SQL — это протокол, который работает поверх Flight и стандартизирует взаимодействие с базами данных с помощью SQL.
По сути, это спецификация, которая определяет набор стандартных команд, которые должен поддерживать сервер:
Execute(query)
: Выполнить SQL-запрос и вернуть результат в виде потока Arrow.GetTables()
: Получить список таблиц.GetCatalogs()
: Получить список баз данных/каталогов.И другие мета-команды, привычные по ODBC/JDBC.
Flight SQL — это, по сути, "JDBC нового поколения". Он берёт лучшее из старого мира (привычный SQL и стандартные мета-команды) и кладёт это на рельсы сверхбыстрого транспорта Arrow Flight.
Шаг 4: API для разработчика — ADBC
У нас есть формат (Arrow), транспорт (Flight) и протокол запросов (Flight SQL). Чего не хватает? Единого и удобного API для разработчиков на стороне клиента!
Мы же не хотим для каждой базы (DuckDB, Snowflake, Dremio) писать свой код, который дёргает gRPC-ручки Flight SQL? Нам нужен аналог pyodbc
или JDBC Driver Manager
— единый интерфейс, который скрывает за собой всю сложность.
Именно эту роль выполняет ADBC (Arrow Database Connectivity).
ADBC — это стандарт API для доступа к базам данных, который возвращает данные в формате Apache Arrow.

Как это работает:
Ваше приложение (например, на Python) использует API ADBC.
Вы подключаете нужный ADBC-драйвер (например,
adbc_driver_postgresql
илиadbc_driver_duckdb
).Драйвер под капотом уже сам решает, как ему общаться с базой: через Arrow Flight SQL (если база его поддерживает) или через нативный протокол, но с обязательным преобразованием результата в Arrow на выходе.
Для вас как для разработчика всё выглядит просто:
# Условный пример
import adbc_driver_duckdb.dbapi as db
con = db.connect("mydb.duckdb")
cursor = con.cursor()
cursor.execute("SELECT * FROM my_table")
# Получаем не список кортежей, а сразу Arrow Table!
arrow_table = cursor.fetch_arrow_table()
# Которая мгновенно (zero-copy) превращается в DataFrame
df = arrow_table.to_pandas()
Вы пишете код один раз, а потом можете легко переключиться с локального DuckDB на облачный Snowflake, просто поменяв драйвер и строку подключения.
Собираем пазл: Идеальный мир аналитики
Давайте ещё раз взглянем на весь стек и его преимущества:
Приложение (Python, R, Java): Работает с данными через удобный API ADBC.
ADBC Driver: Предоставляет единый интерфейс и общается с базой.
Транспорт (Arrow Flight SQL): Передаёт SQL-запросы и получает в ответ потоки данных в формате Arrow.
База данных: Выполняет запрос и отдаёт результат сразу в формате Arrow, минуя стадию медленной сериализации.
Вся цепочка, от диска в базе данных до оперативной памяти вашего аналитического инструмента, становится максимально быстрой, эффективной и без лишних преобразований.
Заключение: Будущее уже здесь
Конечно, ODBC и JDBC никуда не денутся. Они останутся стандартом для множества легаси-систем и транзакционных нагрузок. Но для мира Big Data и аналитики их время уходит.
Стек Arrow + Flight + Flight SQL + ADBC — это не просто очередной модный фреймворк. Это фундаментальный сдвиг в том, как мы работаем с данными, который устраняет одно из самых главных узких мест в современных data-пайплайнах.
Проекты вроде DuckDB, Dremio, Snowflake, Google BigQuery, Voltron Data и многие другие уже активно внедряют и продвигают эти технологии. Так что, если в следующий раз ваш скрипт для выгрузки данных будет работать мучительно долго, теперь вы знаете, кто виноват и что делать.