1. Mở đầu: Một buổi sáng và cú query “vỡ trận”
Có một buổi sáng như mọi ngày.
Bạn mở laptop, định chỉnh nhẹ vài dòng SQL cho dashboard “Doanh thu theo nền tảng”.
Chỉ vài dòng thôi — thêm TikTok vào logic tính phí.
CASE
WHEN platform = 'Shopee' THEN commission_fee * 0.9
WHEN platform = 'Lazada' THEN commission_fee * 0.85
WHEN platform = 'TikTok' THEN commission_fee * 0.88
END AS adjusted_fee
Chạy thử. Dashboard lỗi.
Bạn lùi lại kiểm tra: query dài 400 dòng, mỗi phần một kiểu CASE WHEN.
Bảng config thì thêm 3 cột mới.
Cả pipeline Airflow phía sau nổ tung vì schema không khớp.
Cảm giác quen không?
Đó chính là khoảnh khắc mọi đội BI đều gặp một lần trong đời:
“Query chạy được” không đồng nghĩa với “Query có thể scale”.
2. Cội nguồn của vấn đề: Khi business logic bị nhúng vào SQL
SQL vốn sinh ra để truy vấn dữ liệu, không phải lưu trữ business rule.
Thế nhưng, trong thực tế, gần như mọi dự án data ở giai đoạn đầu đều bắt đầu bằng:
“Cứ viết CASE trong query đi, chạy được đã!”
Và thế là:
-
Fee khác nhau giữa Shopee và Lazada →
CASE WHEN platform = ... - Chính sách rebate mỗi tháng khác nhau →
CASE WHEN month = ... - Cập nhật đặc biệt cho 1 brand → thêm
AND brand_name != 'Test'
Mỗi logic mới là một lớp “băng keo” dán thêm vào query.
Khi có 10 nền tảng, 20 chương trình, 50 sản phẩm, query ban đầu 100 dòng bỗng thành 1.000 dòng.
Không ai dám động vào nữa.
Cập nhật 1 dòng có thể làm dashboard chết hàng loạt.
3. “Tôi đã tách config ra bảng riêng, sao vẫn vỡ?”
Sau vài lần “toang”, đội bạn quyết định “chuẩn hóa”:
Tạo một bảng config riêng để lưu các rule.
Ví dụ:
SELECT o.order_id, o.platform, o.total_amount * c.rate AS commission_fee
FROM orders o
LEFT JOIN config_commission c ON o.platform = c.platform;
Nghe có vẻ chuyên nghiệp.
Nhưng rồi vài tháng sau, bảng config bắt đầu phình ra:
| platform | rate | effective_date | note | override | version |
|---|---|---|---|---|---|
| Shopee | 0.05 | 2025-01-01 | null | v1 | |
| Lazada | 0.04 | 2025-01-01 | test | true | v2 |
| TikTok | 0.03 | 2025-02-01 | new | null | v3 |
Cột mới, version mới, cấu trúc mới.
Query join theo platform không còn chạy đúng, vì:
-
Cột key đổi tên (
platform→channel_code) - Có nhiều record cho cùng 1 platform → join ra nhiều dòng
- Cần filter thêm
effective_date→ lại thêm WHERE
Kết quả:
Query ban đầu tưởng tách config để dễ quản lý, nhưng thực tế lại vỡ cấu trúc.
Vì SQL gốc vẫn đang phụ thuộc chặt vào schema của bảng config.
4. Khi hệ thống bắt đầu “không thể scale”
Hãy tưởng tượng bạn phải nhân đôi hệ thống:
- 10 nền tảng thương mại điện tử.
- 5 warehouse khác nhau.
- 3 nhóm phí (commission, logistic, rebate).
- 2 version bảng config (v1, v2 – mỗi team 1 bản).
Tổng cộng: 10 × 5 × 3 × 2 = 300 biến thể logic.
Với cách làm hiện tại, bạn sẽ cần:
- 300 dòng CASE WHEN hoặc
- 300 biến thể JOIN khác nhau.
Mỗi lần có logic mới, bạn phải:
- Chỉnh query.
- Test lại toàn bộ DAG.
- Re-deploy dashboard.
Đó là lúc hệ thống không còn khả năng scale — không phải vì dữ liệu lớn, mà vì logic không tách lớp.
5. Dấu hiệu nhận biết “query sắp vỡ”
Một số dấu hiệu kinh điển:
| Dấu hiệu | Mô tả thực tế |
|---|---|
CASE WHEN xuất hiện ở hơn 3 nơi |
Bạn đang hard-code logic lặp lại |
| Bảng config có hơn 10 cột, mỗi cột là một rule | Config không còn là data, mà là logic disguised |
| Cần chỉnh query mỗi khi có brand mới | Rule không còn tách biệt với business dimension |
| Không ai dám đụng vào file SQL gốc | Query đã thành “black box” |
6. Cốt lõi của vấn đề: SQL không có “semantic layer”
Cách bạn viết query cho thấy bạn đang làm việc ở tầng nào:
| Tầng | Mục tiêu | Công cụ đúng |
|---|---|---|
| Raw Data | Lưu trữ | Tables |
| Transformation | Chuẩn hoá, tính toán | SQL / dbt / ETL |
| Semantic Layer | Mô tả business rule | View / Model / Config |
| Visualization | Hiển thị | Power BI / Looker / Tableau |
Phần lớn team BI mắc lỗi:
Gộp cả 3 tầng đầu vào 1 query duy nhất.
Hậu quả: query vừa lấy dữ liệu, vừa tính toán, vừa chứa logic dẫn đến không thể maintain, không thể scale, không thể audit.
7. Một ví dụ thực tế từ dự án BI
Trong dự án ERP reconciliation, có logic:
- Nếu order Shopee, fee = NMV * 5%
- Nếu Lazada, fee = NMV * 4%
- Nếu TikTok, fee = NMV * 3%
- Nếu RTV (return-to-vendor), fee = 0
Query ban đầu:
SELECT order_id,
CASE
WHEN platform = 'Shopee' THEN nmv * 0.05
WHEN platform = 'Lazada' THEN nmv * 0.04
WHEN platform = 'TikTok' THEN nmv * 0.03
WHEN order_type = 'RTV' THEN 0
END AS platform_fee
FROM reconcile_data;
Sau 3 tháng, team thêm 2 nền tảng mới.
Thêm vài chương trình rebate.
Bảng query 200 dòng tăng thành 900 dòng.
Power BI mất 5 phút refresh.
Đến lúc đó, mọi người nhận ra:
Chúng ta không bị “chậm” vì dữ liệu, mà vì cách viết SQL của chính mình.
Bạn đã từng gặp “query vỡ trận” tương tự chưa?Chia sẻ câu chuyện của bạn hoặc cách bạn tổ chức logic trong SQL tại phần bình luận nhé!


1 Nhận xét
Các dự án mình làm đều tách query cho 3 tầng, đối với team BI họ chỉ được lấy data từ view đã được define business rule sẵn. Không biết bạn lấy số liệu từ đầu mà khẳng định phần lơn team BI đều gộp cả 3 tầng vào 1 query nhỉ
Trả lờiXóa