The Real Cost of a Single Insert in Postgres
Bài tóm tắt Tiger Data 2026 2. Tăng trưởng Độ khó: Trung bình
Tiger Data · 2026 · 2. Tăng trưởng · Độ khó: Trung bình — bài gốc
Bài của nhà cung cấp (Tiger Data, trước là Timescale), cuối bài quảng bá engine columnar của họ. Phần đo đạc dùng Postgres 16 mặc định và áp dụng cho mọi Postgres; số liệu là theo Tiger Data. Đi cặp với Tiger Data 2026.
Bối cảnh
- Bảng time-series
device_metricsvới 3 index (khiêm tốn cho loại bảng này), mỗi dòng dữ liệu khoảng 40 byte. - Câu hỏi: một insert thật sự ghi bao nhiêu byte? Tỉ lệ byte vật lý trên byte logic gọi là write amplification.
Thay đổi chính (phân tích chi phí)
- Bản thân dòng: mỗi heap tuple có header 23 byte (các trường cho MVCC như
t_xmin,t_xmax), đệm lên 24, cộng line pointer 4 byte. Dòng 40 byte chiếm 68 byte, khoảng 1,7 lần, dù dữ liệu append-only không bao giờ bị update. - Mỗi index là một insert nữa: Postgres cập nhật mọi index đồng bộ trong cùng transaction. Entry B-tree hai cột khoảng 32 byte; 3 index là 3 lần đi từ gốc xuống lá. Key timestamp tăng dần dồn mọi insert vào lá ngoài cùng bên phải; index có cardinality cao rải insert khắp cây, page cần thường không có sẵn trong
shared_buffers. - WAL: mỗi lần chèn heap và mỗi lần chèn index sinh một bản ghi WAL riêng, phải xuống đĩa trước khi commit trả về. Thêm
full_page_writes: lần sửa đầu tiên của mỗi page sau checkpoint ghi cả page vào WAL, nên lượng WAL vọt lên sau mỗi checkpoint. - Đo được (100.000 dòng, bảng 500.000 dòng): ngay sau
CHECKPOINT: 402.099 bản ghi WAL (4 bản ghi mỗi dòng), 1.448 full page image, 41 MB WAL cho 3,8 MB dữ liệu (khoảng 10,7 lần). Chạy lại không checkpoint: 33 MB (8,7 lần), chỉ 50 full page image. Bỏ cả 3 index: 1 bản ghi mỗi dòng, 9,5 MB (2,4 lần). Theo Tiger Data, khoảng 70% WAL của bảng này là để bảo trì index. - Nhân với tốc độ ingest: khoảng 345 byte WAL cho mỗi dòng 40 byte; 50.000 insert/giây là 17 MB/s WAL cho 2 MB/s dữ liệu, chưa tính autovacuum và query. Mỗi index thêm khoảng một bản ghi và 80 byte mỗi dòng.
- Bốn cách giảm, xếp theo rủi ro tăng dần: (1) gom ghi bằng
COPYhoặc insert nhiều dòng (ít bản ghi WAL và ít commit); (2) bỏ index không dùng (idx_scangần 0 trongpg_stat_user_indexes, kiểm tra counter đã tích luỹ đủ lâu); (3) bậtwal_compression(nén full page image, tốn CPU); (4) tăngmax_wal_size,checkpoint_timeout(ít checkpoint hơn, đổi lại phục hồi sau crash lâu hơn).
Vì sao
- Theo Tiger Data, write amplification là cơ chế nằm dưới phần lớn các "trần ingest": workload trông nhẹ trên giấy vẫn làm bão hoà đĩa. Thêm IOPS nâng trần nhưng không đổi tỉ lệ, nên nâng phần cứng thường chỉ mua được vài tháng.
- Các vòng lặp chồng nhau: nhiều index hơn → nhiều WAL hơn → replica trễ hơn; bloat lại đẩy người ta thêm index.
Bài học cho SWE
- Index là thuế ghi vĩnh viễn: index phục vụ một báo cáo mỗi tuần vẫn tốn một lần đi cây và một bản ghi WAL cho mọi dòng, mãi mãi (Query planner và hiệu năng truy vấn).
- Đo, đừng đoán:
pg_current_wal_lsn()vàpg_stat_walcho biết chính xác một lô insert sinh bao nhiêu WAL. Chạy một lần sau checkpoint, một lần không, một lần bỏ index để thấy từng phần chi phí. - Lượng WAL quyết định cả replica lag và backup, nên chi phí ghi của một index lan sang Failover, replica và dự phòng dữ liệu.
- Khi đã làm cả bốn cách mà tỉ lệ vẫn cao, đó là giới hạn của storage engine (header từng dòng), không còn là cấu hình. Theo Tiger Data, ghi theo lô dạng cột mới kéo tỉ lệ về gần 1:1.
Liên quan
#Postgres#Write amplification#WAL#Index#full_page_writes#Checkpoint#COPY#wal_compression#pg_stat_wal#Time-series
Được nhắc tới trong
Chủ đề (1)
Công ty (1)
Bài tóm tắt (3)