Перейти к содержимому
Последнее обновление

Оптимизация чтения Parquet

Кратко Apache Doris включает нативный векторизованный модуль чтения Parquet на C++ для внешних каталогов и TVF, который обходится без промежуточных преобразований через Java или Arrow. Модуль отсекает целые группы строк и отдельные страницы по статистике самого файла, проверяет предикаты по ID элементов словаря и читает столбцы фильтрации перед столбцами с данными результата. Обращения к удалённому хранилищу объединяются, сокращая число запросов, поэтому большинство запросов завершается без декодирования ненужных столбцов.

Оптимизация чтения Parquet в Apache Doris: нативный векторизованный модуль чтения Parquet на C++, который отсекает группы строк и страницы, напрямую декодирует словари и читает данные результата только после фильтрации.

Зачем использовать модуль чтения Parquet в Apache Doris?​

Нативный модуль чтения Parquet в Apache Doris сокращает три основные статьи затрат при сканировании данных в lakehouse: получение байтов из объектного хранилища, распаковку и декодирование страниц, а также преобразование значений в представление, используемое движком во время выполнения. Таблица Hive или Iceberg в S3 в конечном счёте представляет собой набор файлов Parquet, и наивная реализация чтения несёт все три вида затрат при каждом запросе.

Эти затраты проявляются в ситуациях, знакомых каждому, кто оптимизировал запросы к lakehouse:

  • Фильтр WHERE order_date >= '2026-04-01' сканирует каждую группу строк в каждом файле Parquet, поскольку модуль чтения не проверяет значения min/max для отдельных групп строк в файле.
  • Точечный поиск вида WHERE user_id = 12345 считывает весь столбец user_id, хотя только одна группа строк потенциально может содержать этот ID.
  • Запрос SELECT * к широкой таблице событий в S3 выполняет сотни небольших HTTP GET-запросов на файл, по одному на каждый блок столбца.
  • Предикат вида country = 'JP' требует распаковки и декодирования UTF-8 для миллионов строк, хотя столбец использует словарное кодирование и для получения ответа достаточно одного сравнения целых чисел на строку.

Модуль чтения Parquet в Apache Doris спроектирован так, чтобы избежать каждой из этих проблем ещё до чтения страниц из хранилища.

Что такое модуль чтения Parquet в Apache Doris?​

Модуль чтения Parquet в Apache Doris представляет собой нативный компонент на C++, который читает метаданные Parquet, отсекает данные на всех доступных уровнях детализации (группа строк, страница, словарь, столбец) и декодирует значения непосредственно в тот же формат Block, который использует векторизованный исполнитель. В этом процессе нет промежуточных преобразований через библиотеку Java или Arrow.

Основные термины

  • Row group: единица, на которую разбивается файл Parquet для параллельного чтения. Каждая группа содержит статистику min/max и количества значений NULL по каждому столбцу.
  • PageIndex: необязательная структура Parquet (ColumnIndex + OffsetIndex), предоставляющая ту же статистику на уровне страниц, а также смещение каждой страницы в байтах, чтобы модуль чтения мог перейти прямо к ней.
  • Lazy materialization: чтение в два прохода, при котором сначала декодируются столбцы фильтрации, а затем столбцы с данными результата считываются только для строк, прошедших фильтрацию.
  • Dictionary filtering: однократная проверка предиката по странице словаря блока столбца с последующим сравнением строк с полученным набором ID элементов словаря.

Как работает модуль чтения Parquet в Apache Doris?​

Модуль чтения Parquet в Apache Doris выполняет конвейер из пяти этапов, каждый из которых сокращает объём данных, обрабатываемых на следующем этапе.

  1. Отсечение групп строк. При открытии файла модуль чтения проверяет статистику столбцов каждой группы строк и отбрасывает всю группу, если предикат не может соответствовать её диапазону min/max. На этом же этапе проверяется фильтр Блума Parquet, если он есть в файле. Обе проверки выполняются только по метаданным, до считывания страниц столбцов. Управляется параметрами enable_parquet_filter_by_min_max и enable_parquet_filter_by_bloom_filter.
  2. Отсечение страниц с помощью PageIndex. Для каждой оставшейся группы строк модуль чтения разбирает ColumnIndex и OffsetIndex, чтобы отбросить отдельные страницы, значения min/max которых не могут соответствовать предикату. OffsetIndex задаёт диапазон байтов каждой оставшейся страницы, поэтому модуль чтения переходит прямо к следующей странице, не сканируя отброшенные байты. Включается и отключается параметром конфигурации BE enable_parquet_page_index.
  3. Фильтрация по словарю. Если блок столбца использует словарное кодирование, а предикат представляет собой выражение с обращением к одному столбцу, модуль чтения декодирует только страницу словаря, проверяет по ней предикат и переписывает его для работы с ID элементов словаря. Обработка страниц данных после этого сводится к сравнению целых чисел в упакованном битовом представлении.
  4. Ленивая материализация. Строки, прошедшие фильтрацию, ещё нужно собрать. Модуль чтения разделяет столбцы на столбцы фильтрации (используемые в предикатах) и столбцы с данными результата, декодирует столбцы фильтрации для построения битовой карты отбора строк и только затем считывает столбцы с данными результата для строк, прошедших фильтрацию. Управляется переменной сеанса enable_parquet_lazy_mat, включённой по умолчанию.
  5. Объединение операций ввода-вывода и прямое декодирование. Соседние блоки столбцов внутри группы строк объединяются в одну операцию чтения диапазона байтов, поэтому движок выполняет один HTTP GET-запрос вместо нескольких. Декодированные значения попадают непосредственно в векторизованные столбцы Doris, без промежуточных преобразований через Arrow.

В результате для строк, дошедших до исполнителя, уже подтверждено соответствие условиям, а декодируются только столбцы, необходимые запросу.

Быстрый старт​

SELECT region, count(*) AS orders, sum(amount) AS revenue
FROM s3(
"uri" = "s3://demo-bucket/orders/year=2026/*.parquet",
"format" = "parquet",
"s3.endpoint" = "https://s3.us-east-1.amazonaws.com",
"s3.access_key" = "AK...",
"s3.secret_key" = "SK..."
)
WHERE order_date >= '2026-04-01' AND status = 'PAID'
GROUP BY region;

Ожидаемый результат (фрагмент профиля)

VFileScanNode
FilteredRowGroups: 18 / 24
FilteredPages: 210 / 980
LazyReadFilteredRows: 92.1%
RemoteIOMergedRanges: 14 (from 96 chunks)

Модуль чтения отбросил 18 из 24 групп строк по предикату даты, а затем отбросил 210 страниц в оставшихся группах с помощью PageIndex по столбцу status. Ленивая материализация позволила пропустить декодирование region и amount для 92.1% строк, не соответствующих условиям. Девяносто шесть блоков столбцов были объединены в 14 GET-запросов диапазонов байтов к S3.

Когда следует использовать модуль чтения Parquet в Apache Doris?​

Модуль чтения Parquet в Apache Doris используется автоматически при любом запросе, читающем Parquet, поэтому вопрос в том, как обеспечить условия для его эффективной работы.

Подходит

  • Каталоги Hive, Iceberg, Hudi и Paimon, файлы данных которых имеют формат Parquet.
  • Прямой анализ файлов с помощью TVF s3() и hdfs().
  • Селективные запросы к широким таблицам: фильтры с большим числом предикатов позволяют ленивой материализации пропустить больше данных.
  • Предикаты равенства и диапазона по столбцам, для которых записывающая система сохранила статистику.
  • Строковые столбцы со словарным кодированием и точечными предикатами или предикатами IN.

Не подходит

  • Таблицы, хранящиеся в тысячах крошечных файлов Parquet. Для каждого файла нужно разобрать концевой блок метаданных, а для каждого блока столбца требуется как минимум одно чтение диапазона байтов; основную долю затрат составляют накладные расходы на обработку отдельных файлов. Укрупняйте файлы до размеров от 128 MB до 1 GB.
  • Файлы, записанные без статистики столбцов или PageIndex. У модуля чтения нет данных для отсечения, и он переходит к полному сканированию. Включите сбор статистики в записывающей системе (Spark 3.2+ и parquet-mr 1.11+ записывают PageIndex).
  • Селективные предикаты по глубоко вложенным полям структур. Некоторые оптимизации (индекс страниц, фильтрация по словарю) отключены для сложных типов; модуль чтения полностью обходит строки, прошедшие фильтрацию. По возможности сократите глубину вложенности при обращении к данным или используйте столбцы верхнего уровня.
  • Столбцы DATETIME, записанные в формате INT96 старыми реализациями записи Hive. Статистика INT96 часто оказывается повреждённой, поэтому модуль чтения не выполняет для неё отсечение по min/max. Если вы управляете записывающей системой, записывайте временные метки в формате INT64. См. примечания об INT96 в документации по каталогу Hive.

Дополнительные материалы​

  • Справочник по формату файлов Parquet: доступные пользователю настройки (enable_parquet_lazy_mat, enable_parquet_page_index, параметры конфигурации BE для размера буфера) и поддержка в разных версиях.
  • Анализ файлов в S3/HDFS: как напрямую запрашивать файлы Parquet с помощью TVF s3() и hdfs().
  • Отсечение данных: общее описание того, как Doris пропускает чтение данных; модуль чтения Parquet представляет собой один из уровней этого механизма.
  • Векторизованное выполнение: движок, для которого модуль чтения декодирует данные, и причины, по которым важно избегать промежуточных преобразований через Arrow.
  • Кеш данных: когда следует кешировать декодированные страницы Parquet локально, чтобы при повторных сканированиях полностью избежать чтения из удалённого хранилища.
  • Кеш метаданных: кеш на стороне FE для схемы, разделов и списков файлов, от которого зависит отсечение данных в модуле чтения Parquet.
  • Multi-Catalog: как таблицы Parquet в S3, HDFS, Hive, Iceberg и Paimon подключаются к Doris.
  • Интеграции каталогов: справочник по коннекторам для отдельных источников каталогов, содержащих файлы Parquet.
  • Построение lakehouse нового поколения (блог Apache Doris): исходная общедоступная публикация о нативном модуле чтения Parquet.
  • Iceberg: формат таблиц lakehouse, сканирование файлов Parquet в котором эта оптимизация ускоряет наиболее непосредственно.