сеньорчикОткрыть в Telegram
← вся теориятеория к собесу · Spark и большие данные

Форматы файлов и хранение данных

Форматы файлов: колоночные для аналитики

Формат хранения решает, сколько запрос прочитает с диска. Собес проверяет, понимаешь ли ты, почему parquet - стандарт аналитики, а CSV в озере - только в зоне приёма.

Стержень: колоночный формат читает нужные колонки и скипает блоки по статистикам; строчные и текстовые форматы - для обмена, не для хранения аналитики.

// Формулировки: «почему parquet, а не CSV?», «что такое predicate pushdown?», «какой формат сплиттабельный?».

Parquet, ORC, Avro

Parquet - колоночный стандарт аналитики: читает только избранные колонки, сжимает по колонкам (однотипные данные жмутся лучше) и хранит статистики min/max в футере, чтобы пропускать целые row groups при чтении.

ORC - колоночный аналог из мира Hive (stripes, индексы, ACID в Hive); в Spark-стеке дефолт parquet, в Hive-наследии встречается ORC. Avro - строчный формат со схемой в файле: удобен для поточной записи и эволюции схемы, стандарт обмена для Kafka, но для аналитики проигрывает колоночным.

// Row group - единица чтения parquet (обычно 128 МБ): predicate pushdown скипает группы по статистикам, а сортировка данных по фильтруемой колонке усиливает этот скип.

row group
блок строк parquet со статистиками по колонкам
predicate pushdown
пропуск блоков по min/max при чтении
ACID
atomicity, consistency, isolation, durability

Текст, сжатие, сплиттабельность

CSV и JSON - форматы обмена, а не хранения: нет типов и схемы, нет колоночного сжатия, парсинг дорог. В озере им место только в landing-зоне, где данные лежат как пришли.

Сжатие влияет на параллелизм: snappy и zstd в parquet сплиттабельны (жмут внутри блоков), поэтому файл читается кусками параллельно. А gzip-файл целиком не сплиттабелен - его читает одна таска, и параллелизм теряется.

// Отсюда двойная беда гигантского gzip-CSV: и парсинг текста дорог, и весь файл жуёт один поток. Аналитику держат в parquet.

splittable
файл можно читать параллельно кусками
landing zone
зона приёма сырых файлов как пришли

Размер файла и партиции-каталоги

Размер файла держат в диапазоне 128 МБ – 1 ГБ. Мелкие файлы - оверхед метаданных и тасков (тысяча файлов = тысяча задач на листинг и открытие); гигантские несплиттабельные - потеря параллелизма.

Партиционирование каталогами (dt=2026-07-08/) даёт pruning уже на уровне листинга директорий - запрос за дату не листит чужие папки.

// Но высококардинальный ключ в каталогах-партициях (user_id) убивает файловую систему миллионами директорий. Партиционируют по низкокардинальным осям вроде даты, а стриминг мелкими файлами регулярно компактят.

каталог-партиция
dt=.../ - pruning на уровне листинга директорий
compaction
склейка мелких файлов стриминга в крупные

Как отвечать: «Почему parquet, а не CSV для аналитики?»

Потому что аналитические запросы читают несколько колонок из широкой таблицы и фильтруют по диапазонам, и колоночный parquet ровно под это заточен. Он хранит данные по колонкам, поэтому запрос читает с диска только нужные поля, а не всю строку. Однотипные данные в колонке жмутся в разы лучше, чем вперемешку. И у него есть статистики min/max по row group в футере, так что при фильтре движок пропускает целые блоки, не читая их, это predicate pushdown. CSV всего этого лишён: нет схемы и типов, значит каждый запрос парсит текст, читает весь файл целиком, колонки не отделить и толком не сжать. Плюс большой gzip-CSV ещё и не сплиттабелен - его жуёт одна таска. Поэтому CSV я держу только в landing-зоне как формат приёма, а для хранения и чтения аналитики - parquet.

Почему это сильный ответ: три конкретных преимущества parquet (колоночное чтение, сжатие, pushdown по статистикам) против недостатков CSV (парсинг, полное чтение, несплиттабельность) с правильной ролью CSV - приёмная зона.

На чём валят

  • Хранить аналитику в CSV - платишь парсингом и полным чтением каждый запрос.
  • Гигантский gzip-CSV - весь файл читает одна таска.
  • Партиционировать каталоги по user_id - файловая система умирает от директорий.
  • Писать parquet россыпью килобайтных файлов из стриминга без компакции.
  • Менять типы колонок между записями без плана эволюции схемы - читатель падает на merge схем.

Проверьте себя

Пять вопросов из банка по этой подтеме. Всего их 12, остальные разбираются в тренажёре.

  1. #file_formats_storage1 / 5
    Что такое predicate pushdown и partition pruning при чтении данных?
    A)Фильтр применяется при чтении: лишние партиции и колонки не читаются
    B)Spark сначала читает весь датасет целиком, а фильтр применяет в конце
    C)Pushdown ускоряет запись данных, но не их чтение
    D)Partition pruning работает для строковых форматов вроде CSV
    показать ответ и разбор
    +A)Фильтр применяется при чтении: лишние партиции и колонки не читаются

    // разбор: Движок «проталкивает» условие фильтра к источнику: по статистике Parquet и структуре партиций он пропускает целые файлы, row-группы и колонки ещё до загрузки в память. Если данные партиционированы по колонке, по которой фильтруешь, читается лишь нужная партиция — это часто важнее самого движка вычислений.

  2. #file_formats_storage2 / 5
    Что такое проблема мелких файлов (small files problem)?
    A)Множество мелких файлов читается быстрее, чем несколько крупных
    B)Тысячи крошечных файлов = оверхед открытия и раздутые метаданные
    C)Размер и число файлов вообще не влияют на скорость распределённого чтения
    D)Проблема мелких файлов есть в реляционных СУБД, но не в Spark
    показать ответ и разбор
    +B)Тысячи крошечных файлов = оверхед открытия и раздутые метаданные

    // разбор: Каждый файл — это задача на планирование, открытие и запись метаданных. Тысячи крошечных файлов (типичный результат частых стриминговых записей или переизбытка партиций) забивают планировщик и namenode метаданными, и джоба тратит время на оверхед, а не на счёт. Лечение — периодическая компакция мелких файлов в крупные.

  3. #file_formats_storage3 / 5
    Чем bucketing отличается от партиционирования при хранении данных?
    A)Bucketing и партиционирование — это два близких названия одного приёма
    B)Партиционирование раскладывает по хешу в фиксированное число корзин, а bucketing — по значению в папки
    C)Bucketing применим к текстовым CSV-файлам, но не к Parquet
    D)Партиции — папки по значению колонки; бакеты — фиксированное число корзин по хешу (ускоряет join)
    показать ответ и разбор
    +D)Партиции — папки по значению колонки; бакеты — фиксированное число корзин по хешу (ускоряет join)

    // разбор: Партиционирование кладёт данные в папки по значению колонки (хорошо для фильтрации, но плодит папки при высокой кардинальности). Bucketing распределяет данные по фиксированному числу корзин по хешу ключа. Если обе таблицы забакетить по ключу join одинаково, соединение по нему не требует shuffle — записи с одним ключом уже лежат в парных бакетах.

  4. #file_formats_storage4 / 5
    Чем ORC похож на Parquet и когда что выбирают?
    A)ORC — строковый (row) формат, а Parquet — колоночный, отсюда и вся разница в скорости между ними
    B)Parquet не поддерживает сжатие и статистику блоков, тогда как ORC поддерживает и то, и другое
    C)Оба колоночные, сжатые, со статистикой и pushdown; выбор чаще по экосистеме (ORC — мир Hive, Parquet — Spark/шире)
    D)ORC и Parquet идентичны во всём, это по сути один формат под двумя именами
    показать ответ и разбор
    +C)Оба колоночные, сжатые, со статистикой и pushdown; выбор чаще по экосистеме (ORC — мир Hive, Parquet — Spark/шире)

    // разбор: ORC и Parquet — оба колоночные форматы со сжатием, встроенной статистикой (min/max по блокам для skipping), поддержкой вложенных типов и predicate pushdown; по характеристикам они близки, и для аналитики оба сильно лучше строкового CSV. Различия в основном экосистемные и по нюансам: ORC исторически тесно связан с Hive/Hadoop-стеком и иногда чуть лучше жмёт, Parquet — фактический стандарт в Spark и шире поддержан инструментами/облаком. На практике выбор диктует окружение и совместимость, а не радикальная разница в скорости.

  5. #file_formats_storage5 / 5
    Когда выбирают строковый Avro вместо колоночного Parquet?
    A)Avro колоночный, поэтому он быстрее Parquet на аналитических запросах по колонкам
    B)Avro не поддерживает схему, поэтому его берут для временных данных без структуры
    C)Avro применяют для сжатия готовых Parquet-файлов перед архивацией на диск
    D)Когда пишут/читают запись целиком и важна эволюция схемы: стриминг, обмен сообщениями, сериализация — там Avro (row) удобнее
    показать ответ и разбор
    +D)Когда пишут/читают запись целиком и важна эволюция схемы: стриминг, обмен сообщениями, сериализация — там Avro (row) удобнее

    // разбор: Avro — строковый (row-oriented) бинарный формат со схемой и хорошей поддержкой её эволюции (добавление/удаление полей с дефолтами). Он выигрывает там, где работают с записью целиком и много пишут: потоковая передача (Kafka + Schema Registry обычно на Avro/Protobuf), обмен сообщениями, сериализация событий, write-heavy загрузка. Колоночный Parquet, наоборот, оптимален для аналитических чтений подмножества колонок по многим строкам. Типичный конвейер: сырьё/поток — в Avro, а для аналитики его перекладывают в Parquet.

дальше

Теорию прочитали. Навык ставится повторением

В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.