Phần 2: Từ Query Chạy Được đến Hệ Thống Sống Được

1. Câu chuyện thật: Khi Shopee đổi rule, hệ thống “vỡ” trong 2 giờ

Tháng 3/2024, team BI của một công ty e-commerce đang vận hành hệ thống reconciliation doanh thu cho các nền tảng: Shopee, Lazada và TikTok Shop.

Rule gốc khá đơn giản:

  • Commission fee = NMV * rate theo từng platform.
  • Rate được hard-code ngay trong SQL.

Query chính dài hơn 800 dòng, chạy mỗi đêm để cập nhật dashboard revenue.
Một buổi sáng, Shopee thay đổi cách tính phí:

Từ “5% cố định” → “3% cho order dưới 500k, 6% cho order trên 500k”.

Chỉ 1 thay đổi nhỏ, nhưng hệ thống vỡ hàng loạt:

  • Airflow DAG fail do CASE WHEN không match logic mới.
  • Power BI hiển thị commission sai → lệch hàng trăm triệu.
  • Accounting phải tạm dừng reconciliation 2 ngày.

2. Phân tích nguyên nhân

Khi review pipeline, nhóm phát hiện:
  • SQL hard-code trực tiếp:
    CASE 
      WHEN platform = 'Shopee' THEN nmv * 0.05
      WHEN platform = 'Lazada' THEN nmv * 0.04
      WHEN platform = 'TikTok' THEN nmv * 0.03
    END AS commission_fee
    
  • Không có bảng rule riêng → mọi thay đổi phải sửa query.
  • Rule cũ không versioned, không có effective_date → không thể audit dữ liệu tháng trước.
  • Shopee đổi rule giữa tháng → query chỉ chạy đúng một nửa tháng, nửa còn lại sai.

Tóm lại: hệ thống phụ thuộc hoàn toàn vào query, chứ không phải dữ liệu.

3. Giải pháp refactor: chuyển logic sang config-driven model

Team quyết định refactor toàn bộ tầng logic trong 3 bước.

Bước 1: Chuẩn hóa bảng config

Tạo bảng config_commission_rules trong schema data_config, chứa thông tin theo phiên bản và thời gian hiệu lực:

platform min_amount max_amount rate effective_date expiry_date version
Shopee 0 500000 0.03 2024-03-01 9999-12-31 v2
Shopee 500000 999999999 0.06 2024-03-01 9999-12-31 v2
Lazada 0 null 0.04 2024-01-01 9999-12-31 v1
TikTok 0 null 0.03 2024-01-01 9999-12-31 v1

Rule mới giờ được lưu trong data, không nằm trong query.
Bảng này được upload định kỳ từ Excel (Accounting quản lý), rồi sync vào Postgres bằng Airflow job.

Bước 2: Tạo view logic – tách khỏi query chính

Tạo view vw_commission_rate:

CREATE OR REPLACE VIEW data_config.vw_commission_rate AS
SELECT
  platform,
  min_amount,
  max_amount,
  rate,
  effective_date,
  expiry_date
FROM data_config.config_commission_rules
WHERE CURRENT_DATE BETWEEN effective_date AND expiry_date;

→ View này đóng vai trò "semantic layer", cung cấp rule đang hiệu lực.
→ Khi rule mới được cập nhật, view tự động phản ánh đúng mà không cần deploy SQL.

Bước 3: Viết lại query tính phí theo modular logic

Query reconciliation refactor lại:

SELECT 
  o.order_id,
  o.platform,
  o.nmv,
  o.order_created_date,
  o.order_amount,
  c.rate AS commission_rate,
  o.nmv * c.rate AS commission_fee
FROM data_warehouse.reconcile_order_raw o
LEFT JOIN data_config.vw_commission_rate c
  ON o.platform = c.platform
 AND o.order_amount BETWEEN c.min_amount AND c.max_amount
 AND o.order_created_date BETWEEN c.effective_date AND c.expiry_date;
Điểm khác biệt:
  • Không còn CASE WHEN.
  • Có thể thêm rule mới mà không sửa query.
  • Có thể audit version cũ bằng cách filter theo version hoặc effective_date.

4. Kết quả sau khi refactor

Hạng mục Trước refactor Sau refactor
Số dòng query ~850 dòng 240 dòng
Thời gian fix rule mới 2 ngày 15 phút
DAG fail khi Shopee đổi rule Có (2 lần/tháng) 0 lần
Business chủ động thay rule Không Có (qua Excel config)
Power BI refresh 7 phút 2 phút (do query nhẹ hơn)

5. Mở rộng: Ứng dụng semantic layer & dbt

Sau 3 tháng, team mở rộng mô hình này thành tầng semantic chung cho toàn bộ business rule:

  • vw_commission_rate – rule phí nền tảng
  • vw_logistics_fee_rule – rule vận chuyển
  • vw_rebate_rule – rule rebate theo brand

Các view được tạo bằng dbt models với version control.
Khi có rule mới, chỉ cần merge pull request.

Cấu trúc thư mục dbt:

models/
 ├── staging/
 │    ├── stg_orders.sql
 │    └── stg_config_rules.sql
 ├── intermediate/
 │    ├── int_orders__with_commission.sql
 │    ├── int_orders__with_logistics.sql
 ├── marts/
 │    └── finance__reconciliation_summary.sql

Lúc này, query trong Power BI chỉ cần:

SELECT * FROM finance__reconciliation_summary

Không còn logic nghiệp vụ trong dashboard.
Mọi thứ được quản lý version, có test, có lineage.

6. Lợi ích ngoài mong đợi

Refactor này không chỉ giảm lỗi, mà còn mang lại nhiều lợi ích “vô hình”:

  • Accounting chủ động thay đổi rule mà không cần IT support.
  • Ops có thể mô phỏng rule mới để test KPI trước khi áp dụng.
  • BI team tiết kiệm 4–6 giờ mỗi tuần không phải fix query.
  • Data lineage rõ ràng – có thể truy ngược xem order tháng 4 dùng rule nào.
  • Audit dễ dàng khi so sánh version v1 vs v2.

7. Bài học rút ra

“Query chạy được không có nghĩa là hệ thống có thể sống được.”

Từ một case thực tế, team rút ra 3 nguyên tắc vàng:

  1. Logic là data, không phải code.
    → Nếu business có thể thay rule, rule đó nên nằm trong bảng.
  2. Query chỉ nên thể hiện quan hệ, không nên thể hiện policy.
    → Policy = config. Relation = query.
  3. Scale bắt đầu từ cấu trúc, không phải từ công cụ.
    → Dùng Power BI, dbt hay Snowflake đều vô nghĩa nếu model không chuẩn hoá.

8. Kết luận

Sau khi chuyển sang mô hình config-driven, hệ thống reconciliation của team đã chạy ổn định hơn 6 tháng.
Khi Shopee đổi rule thêm 2 lần, team chỉ cần 5 phút cập nhật file config, không một dashboard nào bị lỗi.

Câu chuyện này là minh chứng rõ ràng rằng:

Scalability trong BI không đến từ việc viết SQL giỏi hơn,
mà đến từ việc tách biệt logic và dữ liệu – thiết kế để thay đổi mà không chạm code.

Xem thêm: Khi SQL không còn scale – câu chuyện thật từ BI
Theo dõi blog Rabit Learn Data để đọc thêm các case study BI & Data Engineering thực tế.

Đăng nhận xét

0 Nhận xét