DHDataHọc
TheoryLesson 3/84 min read+10 XP

Idempotency

Bạn sẽ học được

  • Idempotency là gì trong bối cảnh pipeline.
  • Ba mẫu ghi dữ liệu an toàn khi chạy lại.
  • Vì sao INSERT thường là nguyên nhân gây trùng dữ liệu.
  • Kiểm tra tính idempotent bằng cách chạy hai lần.
  • Áp dụng cho bảng partition và bảng upsert.

Khái niệm cốt lõi

Một task là idempotent nếu chạy lại cùng một logical date cho ra cùng một kết quả, không tạo thêm dữ liệu.

code
Chạy 1 lần:  12.000 dòng
Chạy 2 lần:  12.000 dòng   ← idempotent
Chạy 2 lần:  24.000 dòng   ← không idempotent

Điều này quan trọng vì Airflow sẽ chạy lại: khi task thất bại và retry, khi bạn backfill, khi sửa bug và chạy lại một ngày.

Pipeline không idempotent biến một lần retry thành một sự cố dữ liệu.

Ba mẫu an toàn

1. Xoá partition rồi ghi lại

Phù hợp với bảng partition theo ngày:

code
DELETE FROM fact_orders WHERE order_date = '2026-03-01';

INSERT INTO fact_orders (order_date, order_id, amount)
SELECT order_date, order_id, amount
FROM staging_orders
WHERE order_date = '2026-03-01';

Hai câu trong một transaction. Nếu INSERT lỗi, DELETE phải rollback, nếu không ngày đó mất sạch dữ liệu.

2. MERGE (upsert)

Phù hợp khi bảng không partition hoặc cần cập nhật từng dòng:

code
MERGE INTO fact_orders AS t
USING staging_orders AS s
  ON t.order_id = s.order_id
 AND t.order_date = s.order_date
WHEN MATCHED THEN
  UPDATE SET amount = s.amount, updated_at = now()
WHEN NOT MATCHED THEN
  INSERT (order_date, order_id, amount, updated_at)
  VALUES (s.order_date, s.order_id, s.amount, now());

Điều kiện ON phải là khoá duy nhất. Nếu khoá trùng trong staging, MERGE có thể lỗi hoặc cập nhật nhiều lần.

3. Ghi ra bảng mới rồi đổi tên

Phù hợp với bảng lớn, tránh khoá bảng lâu:

code
CREATE TABLE fact_orders_new AS SELECT ...;
-- kiểm tra số dòng
DROP TABLE fact_orders;
ALTER TABLE fact_orders_new RENAME TO fact_orders;

Cần cẩn thận với quyền, view phụ thuộc và thời điểm đổi tên.

Vì sao INSERT gây trùng

code
INSERT INTO fact_orders
SELECT * FROM staging_orders WHERE order_date = '2026-03-01';

Chạy lần đầu: 12.000 dòng. Retry: thêm 12.000 dòng nữa. Không có lỗi nào được báo — bảng chỉ đơn giản là có gấp đôi.

Đây là lỗi nguy hiểm nhất vì im lặng. Số liệu dashboard sai nhưng pipeline vẫn xanh.

Bảng tạm và kiểm tra trước khi ghi

Mẫu an toàn hơn cho dữ liệu lớn:

code
BEGIN;

CREATE TEMP TABLE stg AS
SELECT * FROM raw_orders WHERE order_date = '2026-03-01';

-- kiểm tra
-- SELECT COUNT(*) FROM stg;  -- phải > 0

DELETE FROM fact_orders WHERE order_date = '2026-03-01';
INSERT INTO fact_orders SELECT * FROM stg;

COMMIT;

Nếu số dòng bằng 0 do nguồn lỗi, dừng lại thay vì xoá sạch ngày đó. Một DELETE không có INSERT tương ứng là thảm hoạ khó phát hiện.

Kiểm tra idempotency

Chạy task hai lần cho cùng logical date, rồi so sánh:

code
SELECT
  COUNT(*) AS so_dong,
  COUNT(DISTINCT order_id) AS so_dong_khac_nhau,
  SUM(amount) AS tong
FROM fact_orders
WHERE order_date = '2026-03-01';

Sau lần hai, cả ba số phải giữ nguyên.

Kiểm tra bổ sung: so sánh checksum giữa hai lần chạy, hoặc đối chiếu tổng với nguồn.

Những thứ khó idempotent

Thành phầnVấn đềCách xử lý
Gửi email/SlackGửi lại nhiều lầnGhi cờ đã gửi
Gọi API tính tiềnTính hai lầnDùng idempotency key
Sinh ID tự tăngID khác nhau mỗi lầnDùng khoá nghiệp vụ
Ghi file có timestampNhiều file trùngGhi theo partition cố định

Với tác dụng phụ ra ngoài, idempotency không thể đảm bảo bằng SQL — cần khoá hoặc cờ trạng thái ở hệ thống đích.

Lỗi thường gặp

  • INSERT không xoá partition: trùng dữ liệu khi retry.
  • DELETE và INSERT ngoài transaction: mất dữ liệu nếu lỗi giữa chừng.
  • Không kiểm tra số dòng staging: xoá sạch ngày khi nguồn rỗng.
  • MERGE với khoá không duy nhất: lỗi hoặc cập nhật sai.
  • Ghi file theo timestamp: không ghi đè được.
  • Retry áp cho task gửi thông báo: gửi nhiều lần.

Thực hành

  1. Viết DELETE + INSERT trong một transaction.
  2. Viết MERGE theo order_id.
  3. Chạy thử hai lần và so sánh số dòng.
  4. Thêm kiểm tra staging rỗng trước khi xoá.
  5. Liệt kê ba tác dụng phụ ngoài database cần xử lý riêng.

Lỗi thường gặp

Triệu chứngNguyên nhânCách sửa
Số dòng tăng gấp đôiINSERT thuầnXoá partition trước
Ngày mất sạch dữ liệuLỗi giữa DELETE và INSERTDùng transaction
Tổng tiền sai sau retryGhi trùngKiểm tra khoá duy nhất
Email gửi hai lầnRetry task thông báoGhi cờ đã gửi
File trùng trong S3Tên có timestampGhi theo partition

Tóm tắt

  • Idempotent nghĩa là chạy lại không đổi kết quả.
  • Ba mẫu: xoá partition, MERGE, đổi bảng.
  • INSERT thuần là nguyên nhân phổ biến nhất gây trùng.
  • DELETE và INSERT phải nằm trong một transaction.
  • Kiểm tra bằng cách chạy hai lần và so sánh.

Use ← → to move between lessons