DuckDB с нуля: импорт и экспорт данных. Parquet, CSV, JSON и источники HTTP/FS
DuckDB позиционируется как встроенная аналитическая база данных с нативной поддержкой чтения и записи данных напрямую из форматов файлов и сетевых источников. Глава ориентирована на технических специалистов: как проектируются потоки импорта и экспорта, какие форматы стоит использовать в конкретных сценариях, как работать с Parquet, CSV и JSON, а также как подключаться к источникам HTTP и файловой системе. В конце - практические рекомендации по оптимизации и контролю качества данных в локальном анализе.
Краткое введение
DuckDB стремится обеспечить прозрачный и эффективный доступ к локальным данным без развертывания полноценной СУБД-архитектуры. Встроенные функции чтения файлов и поддержка внешних источников позволяют строить аналитические пайплайны, которые не требуют передачи данных в облако или в отдельный кластер. Важнейшая идея - минимизация затрат на ETL: данные остаются в исходном формате, а запросы выполняются непосредственно на источнике через оператор чтения. Это достигается за счет эффективной компрессии столбцов, продвинутого распознавания типов, поддержки схем и возможностей predicate pushdown, а также интеграций с расширениями, которые позволяют работать с удаленными источниками.
Краткое содержание главы
- Архитектура DuckDB для работы с внешними источниками: как считываются Parquet, CSV и JSON, и каким образом открываются HTTP/FS источники.
- Форматы данных и их характеристики: преимущества Parquet, ограничения CSV и возможности JSON, взаимодействие со схемами и вложенными структурами.
- Практические сценарии импорта: импорт Parquet и организация чтения из локальных файлов и удалённых URL-источников.
- Экспорт данных и управление преобразованиями: копирование результатов в Parquet, CSV и JSON, сохранение схем и контроль целостности.
- Рекомендации по оптимизации: поэтапное профилирование, выбираемые настройки форматов, стратегия использования HTTPFS и управление загрузкой.
Архитектура: как DuckDB обрабатывает внешние источники
DuckDB реализует единый движок выполнения запросов, который может обращаться к различным источникам данных через унифицированный план выполнения. Это достигается за счёт:
-
Импортных функций чтения: read_parquet, read_csv, read_json_auto и прочие table functions, которые возвращают виртуальные таблицы на основе внешних файлов или сетевых ресурсов.
-
Расширяемой инфраструктуры файловых систем: поддержка локального FS и внешних источников через расширения (например, httpfs) для доступа по HTTP/HTTPS.
-
Оптимизации на уровне планировщика: predicate pushdown, чтение только нужных столбцов и фильтрация на чтение, чтобы минимизировать объем читаемых данных.
-
Обработки схем и типов: DuckDB выполняет схематизацию на основе содержимого файлов; поддерживает эволюцию схем и вложенные типы Parquet.
-
Важно отметить, что выбор источника (Parquet vs CSV vs JSON vs HTTP/FS) определяет не только формат, но и стратегию чтения, кэширования и верификации данных. Parquet поддерживает столбцовый доступ и эффективное сжатие, что особенно полезно для больших наборов. CSV пропускается сквозь парсинг строк и типов, что требует явной или неявной конвертации после чтения. JSON обеспечивает гибкость вложенных структур, но может потребовать последующей нормализации в таблицу.
-
В контексте архитектуры стоит помнить о разделении ответственности: источники данных должны быть автономны и воспроизводимы, обработка схем - детерминирована, а экспорт - контролируем по форматам и кодировкам. DuckDB обеспечивает баланс между гибкостью и эффективностью за счет встроенных функций чтения и расширений.
Подключение к внешним источникам
DuckDB поддерживает работу с локальными файлами и удалёнными ресурсами. Для чтения удалённых файлов чаще всего применяются стандартные функции чтения, а для URL-источников - расширение httpfs, которое позволяет обойти ограничения обычного файлового ввода. Настройка может выглядеть следующим образом:
INSTALL httpfs; LOAD httpfs;
-
После подключения можно напрямую читать данные по URL:
SELECT * FROM read_parquet('https://example.com/data/sales.parquet'); -
Для CSV:
SELECT * FROM read_csv('https://example.com/data/customers.csv', header=true, delim=','); -
Для JSON:
SELECT * FROM read_json_auto('https://example.com/data/events.json'); -
При работе с локальным FS - аналогично:
SELECT * FROM read_parquet('/data/warehouse/sales/part-000.parquet'); -
DuckDB не требует копирования данных в отдельный кластер: чтение осуществляется напрямую из источника, а результат возвращается как таблица, которую можно немедленно использовать в аналитике.
Производительность и безопасность
- Predicate pushdown: DuckDB отправляет фильтры на уровне источника там, где это поддерживается, что существенно уменьшает объем данных, считываемых в память.
- Эволюция схем: Parquet хранит метаданные и типы, что облегчает адаптацию к изменяющейся схеме. DuckDB поддерживает эволюцию схем и корректное чтение новых столбцов.
- Безопасность HTTP-источников: когда источники доступны через HTTP, следует учитывать аутентификацию, ограничение скорости и контроль доступа. Для закрытых источников применяются сигнатуры, токены или подписанные URL.
- Кэширование и повторная читаемость: локальные файлы и URL-источники могут кэшироваться на уровне оператора чтения; в некоторых сценариях полезно управлять кэшем вручную, чтобы обеспечить твердую повторяемость результатов.
Работа с Parquet: импорт, схемы и особенности
Parquet - колонно-ориентированный формат, оптимизированный под аналитические запросы. Он поддерживает вложенные типы (struct, list, map) и эффективное сжатие. При чтении Parquet DuckDB:
-
Схема файла включена в метаданные; данные читаются по столбцам, что ускоряет процесс и позволяет обрабатывать большие наборы данных без распаковки всей строки.
-
Вложенные структуры можно распаковывать, применяя функции разворачивания (flatten) внутри DuckDB или через последующие SQL-операторы.
-
Поддержка разделения файлов: если Parquet-файлы лежат в директории, DuckDB может обрабатывать набор файлов как единый набор данных, что полезно при партиционировании.
CREATE TABLE sales AS SELECT order_id, customer_id, total_amount, order_date FROM read_parquet('data/sales/part-*.parquet'); -
В приведенном примере DuckDB обрабатывает несколько файлов как единый источник данных. В реальной практике стоит обратить внимание на колонки типов и фильтры для достижения максимальной производительности.
-
Пример использования разделов и фильтров:
SELECT customer_id, SUM(total_amount) AS total_spent FROM read_parquet('data/sales/part-*.parquet') WHERE order_date >= DATE '2023-01-01' GROUP BY customer_id ORDER BY total_spent DESC LIMIT 100; -
Производительность Parquet особенно усилена за счёт сортировки и статистики по столбцам. Если доступ к паркет-файлам планируется часто, целесообразно поддерживать локальный индикатор метаданных, чтобы ускорить повторные запуски.
-
Разделение паркет-данных по каталогам может позволить разделить данные по годам, странам и другим критериям. DuckDB умеет работать с такими структурами, сохраняя производительность за счет раннего применения фильтров на уровне чтения.
Обработки вложенных структур
-
Nested типы в Parquet позволяют сохранять сложные данные. При необходимости они разворачиваются во временные таблицы, где каждая вложенная структура становится отдельной колонкой или набором колонок после разворачивания. Это облегчает последующий анализ и агрегацию.
-
В рамках импортной логики целесообразно заранее определить, какие поля важны для аналитики, чтобы исключить лишние столбцы и снизить объем чтения.
CSV и JSON: особенности и сценарии использования
CSV - простейший и широко распространённый формат. Основные параметры, влияющие на импорт:
-
Заголовки и разделители: header=true/false; delim=',';
-
Кодировка: UTF-8, Cp1251 и т. д.; поведение при неверной кодировке;
-
Типизация: DuckDB делает попытку автоматического определения типов, но в больших наборах может потребоваться явная кастомизация после импорта.
-
Обработка пропусков: пустые значения, специальные маркеры.
CREATE TABLE customers AS SELECT * FROM read_csv('data/customers.csv', header=true, delim=','); -
Практические советы: после импорта CSV полезно выполнить CAST к конкретной схеме, чтобы единожды зафиксировать типы и упростить последующие запросы.
JSON - формат, подходящий для гибких структур, но не столь эффективный для прямого анализа без нормализации. DuckDB поддерживает чтение JSON через read_json_auto и сопутствующие функции для извлечения полей.
CREATE TABLE events AS
## SELECT id, ts, user_id, action
FROM read_json_auto('data/events.json');
-
Развертывание вложенных структур может потребовать использования JSON-парсинга, json_extract_path_text и других функций DuckDB для нормализации секций в табличную форму.
-
В случае больших JSON-файлов разумно сначала распаковать и нормализовать их в промежуточную таблицу, затем выполнять агрегацию и аналитические запросы на компактной схеме.
Импорт и экспорт через HTTP/FS: практические сценарии
-
Локальные файлы дают полный контроль над данными, однако в некоторых сценариях данные доступны через HTTP или хранятся в облачных файловых системах. В DuckDB это поддерживается напрямую через read_parquet/read_csv/read_json_auto и расширение httpfs.
-
Примеры преимущественного использования:
- Быстрый импорт наборов данных, доступных на удалённых серверах для прототипирования или анализа без копирования в локальную файловую систему.
- Непосредственная аналитика над данными в формате Parquet без предварительного конвертирования в другой формат.
- Гибкая работа с JSON-структурами, когда данные поступают по API через HTTP.
-
Важно помнить о требованиях к доступу: для удалённых источников применяются политики аутентификации, ограничения по скорости загрузки и требования к сертификатам. Кроме того, при работе с HTTP-источниками следует учитывать согласованность источника: версии файлов, кэширование и изменение схемы.
-
Эффективная связка: Parquet как основной формат хранения, CSV/JSON как вспомогательные источники для экспорта и интеграции, HTTP/FS - для оперативного доступа к данным без локального копирования.
Экспорт данных: сохранение результатов
DuckDB поддерживает экспорт в различные форматы с помощью команды COPY, что позволяет сохранить результаты запроса в нужном формате. Примеры:
COPY (SELECT * FROM sales_summary) TO 'output/sales_summary.csv' (FORMAT CSV, HEADER=true, QUOTE '"');
-
Экспорт в Parquet:
COPY (SELECT customer_id, total_spent FROM sales_summary) TO 'output/sales_summary.parquet' (FORMAT PARQUET);
-
Экспорт в JSON:
COPY (SELECT json_build_object('customer', customer_id, 'spent', total_spent) AS payload FROM sales_summary) TO 'output/sales_summary.json' (FORMAT JSON); -
Важно обеспечить согласованность схем: экспортируемые форматы должны соответствовать ожидаемой схеме целевого потребителя. При экспорте Parquet DuckDB сохраняет схему столбцов и вложенные структуры, если они существуют, что позволяет сохранить богатство данных.
-
В случаях сложной трансформации перед экспортом целесообразно построить финальную таблицу-результат, применить фильтры, агрегаты и приведение типов, чтобы итоговый файл отражал необходимый уровень агрегации и нормализации.
Практические рекомендации и best practices
- Определяйте формат в зависимости от downstream-потребителя: Parquet для аналитики на локальном уровне, CSV для совместимости, JSON для гибких структур, HTTP/FS - для оперативного доступа.
- Оптимизируйте чтение благодаря фильтрам на уровне источника: используйте predicate pushdown, указывайте только нужные столбцы, применяйте индексацию метаданных Parquet там, где возможно.
- Планируйте схему заранее: если ожидается эволюция схем, проектируйте промежуточные таблицы и версии схем, чтобы минимизировать влияние изменений на пайплайн.
- Учтите уникальные особенности JSON: вложенные типы требуют нормализации; использование json_extract для извлечения отдельных полей улучшает читаемость и производительность.
- Когда работаете с HTTP-источниками, соблюдайте политику безопасности и надёжную аутентификацию; избегайте чтения чувствительных данных без надлежащей аутентификации.
- Регулярно обновляйте DuckDB и используемые расширения, чтобы получать обновления по производительности и безопасности.
- Применяйте практики повторяемости: фиксируйте версии источников и скриптов импорта; используйте единообразные скрипты для развёртывания в разных средах.
Key takeaways
- DuckDB обеспечивает эффективный доступ к внешним данным через встроенные функции чтения и расширения для HTTP/FS, что позволяет работать с Parquet, CSV и JSON без миграций.
- Parquet предоставляет преимущества для аналитики благодаря столбцовому формату, вложенным типам и эффективному predicate pushdown; CSV и JSON требуют дополнительных шагов нормализации и типов.
- Импорт и экспорт - это управляемые операции: используйте read_parquet/read_csv/read_json_auto для загрузки, и COPY для сохранения результатов в нужном формате.
- Расширение httpfs упрощает работу с удалёнными источниками по HTTP/HTTPS; при работе с такими источниками важно учитывать безопасность и аутентификацию.
- Оптимизация чтения достигается через фильтры, выбор нужных столбцов, корректное использование схемы и мониторинг производительности запросов.
- Архитектурно важно проектировать пайплайны так, чтобы данные оставались воспроизводимыми: версии файлов и схемы должны быть фиксированы и документированы.
- Практические сценарии: от прототипирования до полноценных аналитических пайплайнов на локальном устройстве позволяют минимизировать задержки и риски, связанные с перемещением данных.
FAQ
- Что такое httpfs и зачем он нужен в DuckDB?
- httpfs - это расширение DuckDB, позволяющее работать с удалёнными файловыми ресурсами через HTTP/HTTPS, S3 и другие файловые протоколы. Он расширяет возможности встроенного FS-слоя и обеспечивает доступ к данным без локального копирования. Это особенно полезно для прототипирования, аналитики на местах и интеграций с веб-источниками. Установка и загрузка расширения выполняются стандартными командами Install/Load, после чего можно напрямую читать файлы по URL.
- Как выбрать между Parquet, CSV и JSON для импорта?
- Parquet предпочтителен для больших наборов данных и аналитических задач: он поддерживает столбцовый доступ, вложенные структуры и эффективное сжатие, что ускоряет запросы и уменьшает объём чтения. CSV удобен для простоты обмена и совместимости, но требует явной/автоматической типизации и обработки пропусков. JSON полезен для гибких или вложенных структур, но обычно требует нормализации перед долговременной аналитикой. Выбор формата зависит от источника, объёма данных, требований к производительности и целевых сценариев использования.
- Как обеспечить повторяемость загрузок данных?
- Зафиксируйте версии источников (URL, версии файлов или API-эндпоинтов), используйте скрипты миграции схем, сохраняйте промежуточные таблицы и официальные версии импорта. Включайте параметры чтения (headers, кодировки, делимитеры) в конфигурацию импорта и фиксируйте в документации. Для повторяемости полезна фиксация точек входа и контроль версий в системе управления версиями.
- Какие преимущества даёт использование Parquet для больших наборов?
- Parquet обеспечивает эффективный столбцовый доступ, что уменьшает объем чтения и потребления памяти. Он поддерживает схемы и вложенные типы, что удобно для аналитических запросов. Predicate pushdown позволяет перенести фильтры на чтение, ускоряя выборку и уменьшая задержку.
- Как работать с вложенными структурами в Parquet и JSON?
- В Parquet вложенные структуры разворачиваются через соответствующие операции над полями (flattening) или путем создания отдельных представлений/табличной структуры. JSON требует нормализации: извлечение полей через json_extract или read_json_auto, а затем агрегация в таблицу с плоской схемой. В обоих случаях цель - получить табличную форму для удобной аналитики и совместимости with downstream-инструментами.
- Как обеспечить безопасность при работе с HTTP-источниками?
- Используйте аутентифицированные URL, токены, подписанные ссылки и ограничение прав доступа. Следуйте политике безопасности вашей организации и применяйте шифрование в пути передачи данных, если это возможно. Не используйте открытые ссылки без контроля доступа в продакшен-среде.
- Как оптимизировать загрузку больших Parquet-файлов?
- Выберите фильтры на уровне источника, укажите только необходимые столбцы, используйте схемы, предикаты и разделение паркет-файлов (partition pruning). Планируйте чтение по параллельным сегментам, если файл разделён на подфайлы. Также полезно держать локальный кэш метаданных и обновлять его по мере изменений в источнике.
- Можно ли объединять данные из нескольких источников в одном запросе?
- Да. DuckDB поддерживает запросы к нескольким источникам одновременно: можно читать Parquet из локального FS и JSON по HTTP в одном SELECT, затем выполнять агрегацию и формировать итоговую таблицу. Это одна из ключевых возможностей для локального анализа.
- Какие ограничения стоит учитывать при экспорте JSON?
- JSON-файлы часто имеют гибкую структуру, что может приводить к вариативности схемы. При экспорте следует нормализовать данные в плоскую схему, чтобы обеспечить совместимость с потребителями. Также учитывайте размер и глубину вложенности, так как они влияют на размер и читаемость JSON-файлов.
- Какие открытые источники стоит рассмотреть для примеров импорта?
- Среди открытых вариантов можно упомянуть Parquet-данные о продажах в открытых наборах данных, CSV-файлы с демо-набором клиентов и JSON-данные по событиям. В рамках практики полезны минимальные, проверяемые наборы, которые демонстрируют концепции чтения и агрегации, и которые можно воспроизвести на локальном устройстве.



