Xử lý dữ liệu lớn: Parquet, DuckDB và định dạng cột đo thật
Sê-ri đo thật về xử lý dữ liệu lớn với định dạng cột Parquet và công cụ phân tích DuckDB: kích thước file, tốc độ quét, nén, predicate pushdown, vectorized execution, join, partitioning và xử lý dữ liệu lớn hơn RAM, tất cả đo bằng số thật trong Docker.
5/12 phần đã đăng
Lập trình
1
Cột thắng hàng đo thật: cùng 5 triệu dòng sự kiện, Parquet nặng 71 MB còn CSV 327 MB và JSON 637 MB, quét SUM theo nhóm trên Parquet mất 20,8 ms so với 248 ms của CSV, và đọc một cột thì Parquet nhanh hơn 13 lần vì chỉ chạm đúng khối cột cần
Bài mở đầu sê-ri xử lý dữ liệu lớn: vì sao định dạng cột Parquet nhỏ và quét nhanh hơn định dạng hàng CSV và JSON. Đo thật trong DuckDB 2.0 trên 5 triệu dòng sự kiện 7 cột: Parquet 71 MB so với CSV 327 MB (4,6 lần) và JSON 637 MB (9 lần); quét SUM(amount) GROUP BY country mất 20,8 ms trên Parquet so với 248 ms CSV và 357 ms JSON; đọc một cột thì Parquet 18 ms so với CSV 242 ms. Cột nén tốt nhờ dictionary và RLE, quét nhanh nhờ đọc ít byte và chỉ đọc cột cần.
22/09/2026
· 9 phút đọc
2
Nén Parquet hai tầng đo thật: encoding theo cột rồi codec byte, zstd nén còn 33,8 MB nhỏ hơn gzip 37,3 MB mà ghi nhanh hơn bảy lần (240 ms so với 1749 ms), và một cột mười giá trị lặp nhỏ hơn cột năm triệu giá trị duy nhất 417 lần nhờ dictionary
Parquet nén hai tầng: encoding theo cột (dictionary, RLE) giảm kích thước logic trước, rồi codec byte (snappy, gzip, zstd) nén nốt. Đo thật trong DuckDB 2.0 trên 5 triệu dòng: uncompressed 119,9 MB, snappy 71,1 MB, gzip 37,3 MB, zstd 33,8 MB; zstd nhỏ hơn gzip mà ghi nhanh hơn 7 lần (240 ms so với 1749 ms). Dictionary encoding: cột country 10 giá trị nén còn 0,01 MB so với cột id 5 triệu giá trị 4,88 MB, nhỏ hơn 417 lần. Phần lớn lợi ích đến từ tầng encoding, codec chỉ là lớp phủ.
22/09/2026
· 9 phút đọc
3
Predicate pushdown đo thật: Parquet chia dữ liệu thành row group kèm min/max mỗi cột, nên lọc 1% trên cột đã sắp xếp chỉ đọc 2/100 row group (3,6 ms), còn trên cột xáo trộn phải đọc cả 100 khối (51,1 ms), nhanh hơn 14 lần nhờ dữ liệu được gom
Parquet chia dữ liệu thành row group, mỗi khối lưu min/max từng cột trong footer, nên truy vấn có điều kiện lọc bỏ qua được khối không giao với khoảng lọc. Đo thật trong DuckDB 2.0 trên 10 triệu dòng, 100 row group: lọc 1% dữ liệu trên cột sắp xếp tăng dần chỉ chạm 2/100 row group và mất 3,6 ms; cùng điều kiện trên cột xáo trộn chạm 100/100 row group và mất 51,1 ms, chậm hơn 14 lần. Pushdown chỉ nhìn min/max, cực rẻ, nhưng chỉ phát huy khi dữ liệu được gom theo cột lọc.
22/09/2026
· 9 phút đọc
4
Column projection đo thật: trên bảng Parquet rộng 31 cột và 5 triệu dòng, tính tổng một cột mất 17,8 ms còn kéo cả 30 cột mất 388 ms, tỉ lệ theo số cột đọc, trong khi CSV đọc một cột vẫn mất 749 ms vì phải tách cả dòng, nên SELECT sao là phản mẫu
Định dạng cột chỉ đọc đúng cột cần, nên thời gian tỉ lệ với số cột truy vấn, không phụ thuộc độ rộng bảng. Đo thật trong DuckDB 2.0 trên bảng 5 triệu dòng, 31 cột: tính tổng một cột mất 17,8 ms, mười cột 133 ms, cả 30 cột 388 ms; đọc một cột nhanh hơn đọc 30 cột 22 lần. CSV ngược lại: đọc một cột mất 749 ms, cả 30 cột 1121 ms, chọn ít cột gần như vô ích vì cấu trúc hàng. Parquet đọc một cột nhanh hơn CSV 42 lần, và count sao đọc số dòng trong metadata chỉ 1,2 ms.
22/09/2026
· 8 phút đọc
5
DuckDB quét Parquet tại chỗ đo thật: truy vấn thẳng file bằng read_parquet mất 34,6 ms không tốn bước nạp, nạp vào bảng tốn 145 ms một lần rồi query 26,1 ms nên chỉ đáng khi chạy hơn 17 truy vấn, còn lưu .duckdb gốc thì query chỉ 13 ms
DuckDB truy vấn file Parquet trực tiếp mà không cần nạp vào cơ sở dữ liệu trước. Đo thật trên 10 triệu dòng, Parquet 41 MB: quét thẳng bằng read_parquet mất 34,6 ms mỗi truy vấn và không tốn chi phí nạp; nạp vào bảng DuckDB tốn 145 ms một lần rồi mỗi query trong bộ nhớ 26,1 ms. Điểm hoà vốn khoảng 17 truy vấn: dưới mức đó quét thẳng nhanh hơn. Lưu sang định dạng .duckdb gốc 30,8 MB nhỏ hơn Parquet, mở lại query chỉ 13 ms không phải nạp lại. Chọn cách theo số lần truy vấn.
22/09/2026
· 8 phút đọc
Còn 7 phần nữa sẽ lần lượt được đăng.