Learning Platform
Глоссарий Troubleshooting
Урок 03.02 · 25 мин
Средний
ParquetColumn ChunksProjection PushdownColumn PruningMetadata

Column Chunks

Что такое Column Chunk

Внутри каждого row group данные организованы по колонкам. Column Chunk — это непрерывная последовательность байт на диске, содержащая все значения одной колонки для одного row group.

Если таблица имеет 5 колонок и 3 row group, файл содержит 5 × 3 = 15 column chunks. Каждый chunk хранится контигуально — без прерываний другими данными.

Column Chunks внутри Row Group

Row Group 0 (строки 0–999 999)

Column Chunk: id (INT64)Все значения колонки id для строк 0–999 999. Один непрерывный блок байтов. Содержит dictionary page (если есть) + data pages.
Column Chunk: name (BYTE_ARRAY)Все значения колонки name для тех же строк. Следует сразу за column chunk id — контигуально на диске.
Column Chunk: salary (INT64)Числовые данные — компактно закодированы DELTA_BINARY_PACKED. Меньше, чем строковые колонки.
Column Chunk: department (BYTE_ARRAY)Колонка с низкой кардинальностью (10 уникальных значений). Dictionary encoding сжимает в 50–100x.
Column Chunk: created_at (INT64)Timestamp хранится как INT64 (микросекунды с epoch). Logical type TIMESTAMP в схеме определяет интерпретацию.
NOTE

Каждый column chunk знает свой byte offset в файле. Ридер использует эти offsets из метаданных для seek + read точно нужных байтов — без сканирования файла целиком.

Projection Pushdown

Projection pushdown — это оптимизация, при которой ридер читает только те column chunks, которые нужны запросу. Если запрос SELECT salary, department FROM ... — ридер открывает файл, читает метаданные, находит offsets для salary и department, и читает только эти два column chunk. Остальные 3 колонки не трогаются.

Projection Pushdown: чтение только нужных колонок

Без pushdown (все колонки)

id8 MB прочитано и выброшено — запросу не нужна колонка id
name45 MB прочитано и выброшено — самая большая колонка, полностью бесполезный I/O
salary6 MB — одна из двух нужных колонок. Эти данные реально используются в ответе.
department2 MB — вторая нужная колонка. Вместе с salary — 8 MB полезных данных.
created_at7 MB прочитано и выброшено — ещё один waste I/O.
Прочитано: 68 MB | Использовано: 8 MB (12%)

С pushdown (2 колонки)

idColumn chunk пропущен — ридер не делает seek на этот offset.
name45 MB сэкономлено — самая большая экономия от projection pushdown.
salaryРидер делает seek на offset 55 574 532 и читает 6 MB контигуально.
departmentРидер делает seek на offset 61 865 508 и читает 2 MB. Два seek + два read — всё.
created_atColumn chunk пропущен — ридер уже собрал все нужные данные.
Прочитано: 8 MB | Использовано: 8 MB (100%)

В этом примере projection pushdown экономит 88% I/O. На реальных таблицах с 50–200 колонками, где запрос читает 3–5 колонок, экономия достигает 95–99%.

Метаданные Column Chunk

Каждый column chunk описан структурой ColumnMetaData в Thrift-сериализованном футере файла:

ColumnMetaData {
 type: INT64 // физический тип данных
 encodings: [RLE_DICTIONARY, PLAIN, RLE] // используемые кодировки
 path_in_schema: ["salary"] // путь колонки в схеме
 codec: SNAPPY // алгоритм компрессии
 num_values: 1000000 // количество значений (включая nulls)
 total_uncompressed_size: 8000000 // размер до компрессии
 total_compressed_size: 6000000 // размер после компрессии
 data_page_offset: 55574532 // offset первой data page
 dictionary_page_offset: 55574500 // offset dictionary page (если есть)
 statistics: { // min/max для predicate pushdown
 min: 35000
 max: 250000
 null_count: 42
 }
}
TIP

Вся эта информация доступна без чтения самих данных — она хранится в File Metadata в конце файла. Движки используют statistics для predicate pushdown: если запрос WHERE salary > 300000, а max salary в этом chunk = 250 000 — весь chunk пропускается.

Contiguous Storage и I/O

Column chunk хранится контигуально — все его страницы идут подряд без прерываний. Это критично для производительности:

Контигуальное хранение vs фрагментированное

Parquet: контигуальный chunk

1 seek + 1 sequential read

Один вызов read() читает весь column chunk за один проход — последовательный I/O, максимальная пропускная способность
Column Chunk: salaryВсе pages колонки salary лежат рядом: dict page → data page 0 → data page 1 → ... Ни одного байта чужих данных между ними.

OS readahead эффективен Да

OS readahead работает оптимально — следующие байты в буфере уже предзагружены. Минимальная латентность.

Гипотетический: interleaved

N seeks + N random reads

Данные разных колонок чередуются — нужны seek операции между каждым фрагментом. Случайный I/O — медленно.
Interleaved pagesСтраницы разных колонок перемешаны. Для чтения salary нужно прыгать через чужие данные — random I/O.

Readahead бесполезен Нет

Readahead бесполезен — после каждой страницы идут чужие данные, которые нужно пропустить.

На HDD разница между sequential и random I/O — 100x. На SSD — 5–10x. На сетевом хранилище (S3, GCS) — каждый seek это новый HTTP Range request, что добавляет 50–200 мс латентности.

Column Pruning vs Row Group Pruning

Parquet предлагает два уровня pruning, которые работают вместе:

УровеньЧто пропускаетсяНа основе чегоЭкономия
Column pruningНенужные column chunksСписок колонок в запросе50–99% (зависит от ширины таблицы)
Row group pruningНенужные row groupsmin/max статистики0–99% (зависит от сортировки данных)

При запросе SELECT salary FROM employees WHERE year = 2024:

  1. Column pruning: читаем только salary и year (2 из 50 колонок → 96% экономии)
  2. Row group pruning: пропускаем row groups где year max < 2024 или min > 2024

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

  1. Column Chunk — непрерывный блок байтов на диске, содержащий все значения одной колонки для одного row group
  2. Projection pushdown позволяет читать только нужные column chunks — экономия 50–99% I/O на широких таблицах
  3. Контигуальное хранение обеспечивает sequential I/O и эффективный OS readahead
  4. ColumnMetaData в футере файла содержит offset, размер, кодировку и статистики каждого chunk — доступно без чтения данных
  5. Column pruning + Row group pruning комбинируются для минимизации I/O по обоим измерениям

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

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. Что гарантирует контигуальное (непрерывное) хранение данных column chunk на диске?

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

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

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

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