Learning Platform
Глоссарий Troubleshooting
Урок 02.05 · 25 мин
Средний
MetadataSchemaStatisticsBloom FiltersPredicate Pushdown

Метаданные и схема

Метаданные — скрытая суперсила форматов

Разница между CSV и Parquet — не только в columnar layout и компрессии. Главное преимущество modern formats — встроенные метаданные, которые позволяют движку пропускать данные, не читая их.

CSV-файл — это поток байтов. Чтобы найти нужные данные, нужно прочитать весь файл. Parquet-файл — это структура с оглавлением, статистиками и схемой. Движок может решить, какие блоки читать, до обращения к данным.

Анатомия метаданных

Метаданные в Parquet-файле
Row Group 1Первая группа строк (0–999K). Содержит column chunks для каждой колонки с собственными page-level статистиками.
Row Group 2Вторая группа строк (1M–1.999M). Полностью независима — может быть прочитана и обработана отдельно.
Row Group NКаждый row group — автономная единица. Размер обычно 128–256 MB. Больше row groups = лучший pruning.
После всех данных
Footer (метаданные)Footer — последние байты файла. Содержит схему, статистики по каждому row group и каждой колонке, offsets страниц.

Magic Number (PAR1) + Footer Length

Последние 4 байта — magic number 'PAR1'. Перед ним — длина footer. Движок сначала читает хвост файла, потом принимает решение.

Обратите внимание: footer — в конце файла. Это позволяет записывать данные streaming-образом (append row groups), а метаданные дописать один раз в конце.

Как работает predicate pushdown

Predicate pushdown — механизм, который использует метаданные для пропуска целых блоков данных.

Predicate Pushdown: как метаданные экономят I/O
SELECT * WHERE salary > 100000Запрос ищет записи с salary > 100000. Без метаданных — полный scan. С метаданными — проверяем статистики.
Шаг 1: читаем footer

Footer: min/max статистики по row groups

Footer содержит min/max для каждой колонки в каждом row group. Одно чтение в несколько KB.
Шаг 2: проверяем статистики
Row Group 1Максимальное значение salary в этом row group = 85000. Гарантированно нет записей > 100000 → пропускаем.
Row Group 2Max salary = 150000 > 100000 → возможно есть подходящие записи. Читаем этот row group.
Row Group 3Max salary = 72000 < 100000. Все записи точно не подходят → пропускаем без чтения.
Шаг 3: читаем только нужные

Прочитан 1 из 3 row groups (экономия 66% I/O)

Из 3 row groups прочитан только 1 — экономия 66% I/O. На больших файлах с десятками row groups экономия может достигать 90%+.
TIP

Predicate pushdown работает тем лучше, чем больше данные отсортированы по колонке фильтрации. Если salary отсортирован, row groups содержат непересекающиеся диапазоны — pruning пропускает максимум блоков.

Bloom Filters

Min/max статистики не помогают для equality-запросов на колонках с высокой кардинальностью:

SELECT * FROM events WHERE user_id = 'abc-123-def'

Min/max для user_id: min='aaa...', max='zzz...' — бесполезно, любой row group может содержать этот ID.

Bloom filter — вероятностная структура данных, которая отвечает на вопрос “содержит ли этот блок значение X?”:

  • “Нет” — гарантированно нет, блок можно пропустить
  • “Возможно да” — нужно проверить (может быть false positive)
Bloom Filter в действии
WHERE user_id = 'abc-123-def'Запрос ищет конкретный user_id. Min/max статистики бесполезны — кардинальность слишком высока.
Проверяем bloom filter каждого row group
RG 1: Bloom FilterBloom filter для этого row group не содержит хеш запрошенного user_id → гарантированно пропускаем.
RG 2: Bloom FilterBloom filter говорит 'возможно есть' — нужно проверить. Может быть false positive (1–5% вероятность).
RG 3: Bloom FilterСнова точное 'нет' — пропускаем.

Читаем только RG 2 (экономия 66% I/O)

Из 3 row groups читаем только 1. Bloom filter занимает ~10 KB на row group — ничтожный overhead.
NOTE

Bloom filters не включены по умолчанию — их нужно явно включить при записи для конкретных колонок. Добавляют ~10 KB overhead на row group per column, но экономят гигабайты I/O на point lookups.

Встроенная схема vs внешний реестр

Форматы хранят информацию о типах данных двумя способами:

ПодходПримерыПлюсыМинусы
Встроенная схемаParquet, ORC, AvroФайл самодостаточен, любой может прочитатьSchema evolution сложнее
Внешний реестрKafka + Schema Registry, Hive MetastoreЦентрализованное управление, валидацияЗависимость от реестра
Без схемыCSV, JSONГибкостьSchema drift, нет валидации
Встроенная схема vs Schema Registry

Встроенная (Parquet/ORC)

ФайлСхема записана в footer файла. Reader извлекает типы, имена и nullable-флаги без внешних зависимостей.

Reader: самодостаточное чтение

Любой инструмент (DuckDB, Spark, pandas) может прочитать файл и сразу знает типы колонок.

Внешний (Schema Registry)

Файл/СообщениеДанные содержат только schema ID (4 байта). Полная схема хранится отдельно в реестре.

Schema Registry (HTTP API)

Reader обращается к Schema Registry по сети. Без реестра — данные нечитаемы.

Reader: чтение с зависимостью

После получения схемы из реестра — данные можно десериализовать. Зависимость от внешнего сервиса.

Зачем всё это нужно: полная картина

Объединим все метаданные в один read path:

Metadata-driven Read Path
SELECT name, salary WHERE department = 'Engineering' AND salary > 100000Аналитический запрос с фильтром и проекцией — типичный OLAP-паттерн
1. Column Pruning (из схемы)

Читать только: name, salary, department (3 из 50)

Из 50 колонок читаем только 3: name, salary, department. Остальные 47 не загружаются с диска.
2. Row Group Pruning (min/max stats)

Пропустить row groups без подходящих salary/department

Проверяем salary max и department values по каждому row group. Пропускаем row groups, где нет подходящих записей.
3. Bloom Filter Check (для department)
Bloom filter: department = 'Engineering' в каких RG?Для equality-фильтра department='Engineering' bloom filter даёт точный ответ 'точно нет' для большинства row groups.
4. Page-level Pruning

Пропустить страницы с неподходящими min/max

Внутри выбранных row groups — page-level статистики позволяют пропустить ещё часть страниц.

Результат: 1% данных прочитано с диска

Из терабайта данных реально с диска прочитано несколько мегабайт. Всё остальное отсечено метаданными.
WARNING

Метаданные — не магия. Они работают только если данные организованы: отсортированы, партиционированы, записаны с разумным размером row group. На случайно записанных данных min/max перекрываются и pruning не срабатывает.

Ключевые выводы

  1. Footer — хранит схему, статистики, offsets. Первое, что читает движок. Находится в конце файла.
  2. Min/max статистики — позволяют пропускать целые row groups (predicate pushdown). Эффективны на отсортированных данных.
  3. Bloom filters — вероятностная проверка для equality-запросов. Компенсируют ограничения min/max на колонках с высокой кардинальностью.
  4. Встроенная схема — файл самодостаточен, не нужен внешний реестр. Parquet, ORC, Avro — все используют.
  5. Metadata-driven read — комбинация column pruning + row group pruning + bloom filters + page pruning позволяет читать 1–5% данных вместо 100%.
  6. Сортировка данных — ключ к эффективности метаданных. Без сортировки min/max перекрываются, pruning не работает.

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

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. Parquet footer находится в конце файла, а не в начале. Почему?

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

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

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

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