What Is Inside an Iceberg Table?

Bài tóm tắt DuckDB Labs 2026 3. Quy mô lớn Độ khó: Trung bình

DuckDB Labs · 2026 · 3. Quy mô lớn · Độ khó: Trung bình — bài gốc

Bài khái niệm kiểu hướng dẫn (dùng DuckDB đọc từng lớp file của một bảng Iceberg nhỏ), không phải câu chuyện hệ thống production. Đọc cùng DuckDB Labs 2026, nơi chính DuckDB Labs lập luận cho cách để metadata trong database.

Bối cảnh

  • Bảng Iceberg nhìn như bảng thường khi query, nhưng bên dưới là một cây file trên object storage: một file JSON ở trên, vài lớp Avro ở giữa, Parquet ở dưới. Khi query chậm hay số liệu lạ, cần biết trong cây đó có gì.

Nội dung chính

  • Catalog giữ đúng một trạng thái thay đổi được: con trỏ tới file metadata.json hiện tại của mỗi bảng. Mọi file khác bất biến; mỗi lần đổi bảng ghi file mới bên cạnh file cũ.
  • Commit = dời con trỏ: lần ghi đọc snapshot hiện tại, ghi file dữ liệu và metadata mới, rồi xin catalog dời con trỏ nếu nó vẫn trỏ vào snapshot đã đọc. Hai người ghi cùng xuất phát từ một snapshot thì người sau bị từ chối và phải làm lại trên snapshot mới (optimistic concurrency).
  • Các lớp:
    1. metadata.json: schema, partition spec, danh sách snapshot còn giữ (mỗi snapshot có summary đếm số dòng/file thêm, xoá) và log các file metadata trước. File này lớn dần theo mỗi commit; bảng nhận hàng nghìn commit nhỏ sẽ chậm lúc nạp, phải expire snapshot cũ.
    2. Manifest list (Avro, một file mỗi snapshot): danh sách manifest, kèm khoảng giá trị partition của mỗi manifest để bỏ qua cả manifest.
    3. Manifest (Avro): mỗi dòng một file dữ liệu hoặc file xoá, với giá trị partition, số dòng, cận dưới/trên của từng cột. Engine có thể thêm một manifest mới mỗi lần ghi (commit rẻ, nhưng manifest nhỏ chồng chất làm chậm đọc) hoặc gộp vào manifest có sẵn (ghi đắt hơn, đọc tốt hơn).
    4. File Parquet dữ liệu và file xoá theo vị trí: DELETE/UPDATE không sửa file dữ liệu mà ghi (file, vị trí dòng) cần bỏ qua (merge-on-read). Ghi rẻ, đọc phải ghép, và chi phí tăng theo số file xoá. Iceberg v3 lưu cùng thông tin bằng deletion vector nhị phân trong file Puffin.
  • Bỏ qua file: cận min/max mỗi cột trong manifest cho phép bỏ qua file khi lọc trên cột không phải partition; dữ liệu ghi theo thứ tự của cột hay lọc thì cận hẹp hơn, bỏ được nhiều hơn. Ví dụ trong bài: dữ liệu rải vòng tròn qua các ngày nên cận của ba file gần như trùng nhau.
  • Khi nào cần nhìn vào: query đọc nhiều file hơn mong đợi (so cận với filter); bảng chậm dần (đếm manifest và file xoá); số dòng lạ (xem summary của snapshot); bảng do engine khác ghi.

Vì sao

  • Đặt mọi trạng thái trên object storage dưới dạng file bất biến, chỉ một con trỏ là thay đổi được, cho phép nhiều engine độc lập cùng đọc ghi một bảng mà không cần một server giữ dữ liệu (Tách compute khỏi storage).
  • Cái giá là mỗi commit tạo thêm file metadata, nên ghi nhỏ và nhiều làm phình cả cây: chính là "small files problem" mà streaming vào lake gặp (Pipeline dữ liệu và analytics).

Bài học cho SWE

  • Hiểu đường đi của một query trên lake: catalog → metadata → manifest list → manifest → file. Mỗi lớp có cách bỏ qua riêng (partition theo manifest, cận cột theo file).
  • Bảo trì (expire snapshot, gộp manifest, compaction file xoá) là phần bắt buộc của vận hành lake, không phải tuỳ chọn.
  • Thứ tự ghi dữ liệu quyết định hiệu quả bỏ qua file ngang với partition.
  • Optimistic concurrency qua một con trỏ là đơn giản nhưng người ghi đồng thời nhiều sẽ phải retry nhiều.

Liên quan