Parquet File Format

Overview mental model for Parquet: why it exists, row-based vs column-based contrast, file layout, row groups, column chunks, pages, footer metadata, encoding, compression, and where it sits in lakehouse storage.

Parquet File Format: physical layout cho analytics workload

Vì sao cần Parquet?

Data platform thường có workload kiểu:

ghi theo batch / append nhiều file
đọc lại rất nhiều lần bằng Spark / Trino / DuckDB / BI
query thường scan nhiều rows nhưng chỉ cần một số columns

Nếu lưu bằng CSV/JSON, engine phải parse text, infer/đọc schema yếu, và thường kéo theo nhiều data không cần thiết. Parquet sinh ra để trả lời một nhu cầu cụ thể hơn:

Làm sao lưu dữ liệu dạng bảng trên distributed storage sao cho analytics engine đọc ít bytes hơn, decode ít hơn, và có metadata để prune trước khi scan data thật?

Parquet ở tầng nào?

Parquet là file format, không phải table format. Nó mô tả layout bên trong từng file. Delta Lake/Iceberg/Hudi có thể dùng Parquet làm data file, rồi thêm metadata/transaction/snapshot ở tầng table bên ngoài.

Logical table vs physical file layout

Một table nhìn ở SQL level có vẻ rất đơn giản:

user_idcountryevent_dateamount
1VN2026-06-01100
2US2026-06-01200
3VN2026-06-02300

Nhưng khi persist xuống file, câu hỏi quan trọng là:

Các values được đặt cạnh nhau theo row, theo column, hay theo một layout hybrid nào đó?

Row-based format

Row-based layout đặt các field của cùng một record gần nhau:

[user_id=1, country=VN, event_date=2026-06-01, amount=100]
[user_id=2, country=US, event_date=2026-06-01, amount=200]
[user_id=3, country=VN, event_date=2026-06-02, amount=300]

Nó hợp với mental model “mỗi lần đọc/ghi là một event/record”. Ví dụ:

  • application log;
  • message/event payload;
  • streaming record;
  • row-level serialization.

Nhưng với analytics query:

SELECT sum(amount)
FROM events
WHERE country = 'VN';

engine chỉ cần hai cột countryamount. Nếu file layout ép engine đọc từng row nguyên vẹn, nó dễ đọc dư user_id, event_date, payload, v.v.

Column-based format

Column-based layout đặt values của cùng một column gần nhau:

user_id:    [1, 2, 3]
country:    [VN, US, VN]
event_date: [2026-06-01, 2026-06-01, 2026-06-02]
amount:     [100, 200, 300]

Điểm mạnh:

MechanismVì sao có lợi cho analytics?
Column pruningQuery cần cột nào thì đọc cột đó, tránh kéo theo wide columns không dùng.
Better compressionValues cùng type/domain nằm cạnh nhau nên dictionary/RLE/delta/compression hiệu quả hơn.
Vectorized scanEngine có thể decode/process theo batches của một column thay vì từng object row.
Metadata pruningFormat có thể giữ statistics theo block/row group/page để skip data chắc chắn không match.
Warning

Columnar không phải magic. Nếu data layout trộn lung tung, stats quá rộng, file quá nhỏ/quá nhiều, hoặc query filter không align với layout, Parquet vẫn có thể scan rất nhiều bytes.

Parquet không phải “một cục column cho cả file”

Parquet là columnar, nhưng nó không đơn giản là:

whole file user_id column
whole file country column
whole file amount column

Nó chia file thành row groups. Mỗi row group chứa một batch rows. Bên trong mỗi row group, data được lưu theo column chunks.

Parquet file
├── Row group 1
│   ├── Column chunk: user_id
│   ├── Column chunk: country
│   ├── Column chunk: event_date
│   └── Column chunk: amount
├── Row group 2
│   ├── Column chunk: user_id
│   ├── Column chunk: country
│   ├── Column chunk: event_date
│   └── Column chunk: amount
└── Footer metadata

Mental model:

Parquet = horizontally split into row groups,
          then vertically stored as column chunks inside each row group.

Vì vậy row group không làm Parquet thành row-based. Nó là đơn vị batch/metadata/parallelism/pruning. Bên trong row group vẫn là columnar.

Các concept chính trong Parquet

ConceptMental modelNó giúp gì?
FileMột physical object trên HDFS/S3/local diskĐơn vị storage/list/read ở hệ thống bên dưới
Row groupBatch rows lớn trong fileĐơn vị parallelism, pruning, buffering
Column chunkData của một column trong một row groupColumn pruning: đọc cột cần thiết
PageBlock nhỏ hơn trong column chunkEncoding/compression/page-level read
EncodingCách biểu diễn values trước compressionDictionary, RLE, delta giúp giảm size/CPU/I/O
CompressionNén bytes sau encodingGiảm storage và network/disk I/O
FooterMetadata cuối fileSchema, row groups, column chunks, stats, offsets
Statisticsmin/max/null_count/distinct-ish tùy supportPredicate pruning: skip row group/page/file

Read path simplified

Ví dụ query:

SELECT amount
FROM events
WHERE event_date = '2026-06-27'
  AND country = 'VN';

Engine có thể:

  1. đọc footer để biết schema, row group, offset, stats;
  2. bỏ qua row group có event_date min/max không overlap ngày cần query;
  3. chỉ đọc column chunks liên quan tới event_date, country, amount;
  4. decompress/decode phần còn lại.

Write path simplified

incoming rows

buffer thành row group

tách theo column chunks

encode values

compress pages

tính statistics

ghi data pages + footer metadata

Parquet thường đắt hơn khi write so với dump row/text đơn giản, nhưng trade-off là query sau đó đọc rẻ hơn nhiều.

Write once, read many

Parquet rất hợp với analytics/lakehouse vì dữ liệu thường được ghi theo batch/append rồi đọc lại nhiều lần. Chi phí encode/compress/statistics ở write path được trả để giảm scan I/O, storage size, network, và CPU ở read path.

Parquet trong lakehouse

Trong lakehouse, Parquet thường là data-file layer:

Table format không thay thế Parquet. Nó quản lý tập nhiều Parquet files như một table có snapshot, transaction, schema evolution, partition evolution, manifests/logs, v.v.

My Summary

Parquet nên được hiểu như một physical layout cho analytics:

row-based format: đọc/ghi tiện theo record
column-based format: scan analytics tốt hơn vì đọc theo cột
Parquet: columnar + row groups + pages + footer metadata + encoding/compression/statistics

Điểm quan trọng nhất với data platform không phải “Parquet nhanh”, mà là:

Parquet tạo điều kiện để engine đọc ít bytes hơn, nhưng hiệu quả thật phụ thuộc vào layout, file size, row group size, statistics quality, partitioning/clustering, và table-format metadata ở tầng trên.

Next notes

  • Parquet Row Group and Statistics
  • Later: Parquet encoding/compression, schema evolution, page index/bloom filter, and how Delta/Iceberg consume Parquet metadata.

On this page