Small files problem là khi một bảng gồm rất nhiều file nhỏ (vài KB tới vài MB) thay vì ít file cỡ 128MB–1GB. Tổng dữ liệu không đổi nhưng mọi lần đọc đều chậm đi, vì chi phí liệt kê, mở file và đọc metadata tính theo số file, không theo dung lượng.
Vì sao chậm:
- Engine phải liệt kê và mở hàng chục nghìn file; trên S3 mỗi lần LIST, GET là một request có độ trễ riêng.
- Mỗi file nhỏ thường thành một task; 50.000 task chạy vài giây còn lâu hơn 200 task chạy một phút.
- Parquet nén và lưu thống kê min/max theo khối; file nhỏ nén kém và engine gần như không bỏ qua được khối nào.
- Trên HDFS, mỗi file chiếm một phần bộ nhớ của NameNode.
Nguyên nhân hay gặp: streaming ghi một lần mỗi micro-batch; partitionBy theo cột có quá nhiều giá trị (theo user_id, theo giờ trên bảng ít dữ liệu); job ghi với 200 partition shuffle mặc định trong khi dữ liệu chỉ vài trăm MB.
Xử lý:
- Lúc ghi: repartition theo cột partition hoặc coalesce để mỗi partition ra ít file; dữ liệu ít thì chia partition theo ngày thay vì theo giờ.
- Gom file định kỳ (compaction) bằng lệnh của table format:
-- Delta Lake
OPTIMIZE events WHERE event_date >= '2026-09-01';
-- Apache Iceberg (Spark procedure)
CALL catalog.system.rewrite_data_files(table => 'db.events');- Delta Lake 3.1+ có optimized writes và auto compaction (mặc định tắt) để gom file ngay lúc ghi.
Lưu ý: compaction ghi file mới nhưng chưa xoá file cũ, để time travel vẫn dùng được; phải chạy thêm VACUUM (Delta) hoặc expire snapshots (Iceberg) thì dung lượng mới giảm. Nên chạy compaction trên các partition đã đóng (ngày hôm qua) để không tranh ghi với luồng streaming đang ghi vào partition hôm nay.