Full load đọc lại toàn bộ bảng nguồn mỗi lần chạy. Incremental load chỉ lấy phần mới hoặc thay đổi kể từ lần chạy trước, dựa vào một mốc gọi là watermark (thường là updated_at lớn nhất đã nạp).
Full load đơn giản và luôn đúng, hợp với bảng nhỏ như danh mục tỉnh thành. Bảng giao dịch vài trăm triệu dòng thì full load mỗi đêm vừa chậm vừa đè tải lên nguồn, nên phải chuyển sang incremental.
MERGE INTO dw.orders AS t
USING (
SELECT *
FROM src.orders
WHERE updated_at > (
SELECT COALESCE(MAX(updated_at), TIMESTAMP '1970-01-01') FROM dw.orders
)
) AS s
ON t.order_id = s.order_id
WHEN MATCHED THEN UPDATE SET
status = s.status, amount = s.amount, updated_at = s.updated_at
WHEN NOT MATCHED THEN INSERT (order_id, status, amount, updated_at)
VALUES (s.order_id, s.status, s.amount, s.updated_at);Phải dùng MERGE (upsert) chứ không INSERT, vì một đơn cũ đổi trạng thái sẽ quay lại trong lần lấy sau. dbt làm đúng mẫu này qua materialized='incremental' và unique_key.
Các chỗ dễ sai:
- Bản ghi bị xoá cứng ở nguồn không có updated_at mới nên không bao giờ được lấy → cần soft delete hoặc CDC.
- Lần chạy đầu: bảng đích rỗng thì MAX trả về NULL, updated_at > NULL không khớp dòng nào, nên phải có COALESCE như trên.
- Transaction ghi chậm: dòng có updated_at nhỏ hơn watermark nhưng commit sau khi job đã đọc sẽ bị bỏ sót → lùi watermark vài phút (lookback window) và dựa vào MERGE để không trùng.
Lưu ý: luôn giữ đường chạy full refresh cho bảng incremental, để sửa khi logic đổi hoặc nghi ngờ dữ liệu bị lệch.