Mở đầu — vì sao bài này quan trọng
Ở Bài 8, bạn đã đưa được dữ liệu thô từ nhiều nguồn — đơn hàng, khách hàng, log ứng dụng — vào một kho dữ liệu tập trung như Snowflake hay BigQuery. Nhưng dữ liệu thô gần như không bao giờ dùng được ngay. Nó lộn xộn, trùng lặp, thiếu chuẩn, và mỗi bảng lại nói một "ngôn ngữ" khác nhau. Một cột revenue ở nguồn A tính theo VND đã trừ thuế, còn ở nguồn B lại là USD chưa trừ hoàn tiền. Nếu ai cũng tự viết SQL của riêng mình để "làm sạch" trước khi báo cáo, thì cả tổ chức sẽ có mười phiên bản doanh thu khác nhau — và không ai tin con số nào.
Đây chính là khoảng trống mà data transformation (biến đổi dữ liệu) lấp vào: biến dữ liệu thô thành các bảng sạch, thống nhất, sẵn sàng cho phân tích. Và trong thế giới Modern Data Stack hiện nay, công cụ gần như mặc định để làm việc này là dbt (data build tool).
Điều khiến dbt đặc biệt không phải vì nó "chạy SQL" — bất kỳ ai cũng chạy được SQL. dbt đặc biệt vì nó mang những thực hành tốt nhất của kỹ sư phần mềm — version control, testing, tài liệu tự sinh, tái sử dụng code — vào công việc phân tích dữ liệu vốn trước đây rất hỗn loạn. Sau bài này, bạn sẽ hiểu vì sao một analyst biết dbt lại có giá trị gấp nhiều lần một người chỉ biết viết SQL rời rạc, và bạn sẽ biết cách bắt đầu.
Khái niệm cốt lõi
dbt là gì và không là gì
dbt là công cụ đảm nhận chữ "T" (Transform) trong quy trình dữ liệu. Điểm mấu chốt cần nhớ: dbt không di chuyển dữ liệu và không tự tính toán. Bản thân dbt không có "động cơ" xử lý. Nó chỉ làm một việc: nhận các câu lệnh SQL bạn viết, biên dịch chúng, rồi đẩy xuống cho kho dữ liệu (Snowflake, BigQuery, Redshift...) thực thi. Toàn bộ sức mạnh tính toán nằm ở warehouse; dbt là "nhạc trưởng" điều phối.
Cách tiếp cận này gọi là ELT (Extract → Load → Transform) thay vì ETL truyền thống. Trước đây, ta phải biến đổi dữ liệu ở một máy chủ riêng (bằng công cụ ETL đắt tiền, phức tạp) rồi mới nạp vào kho. Với ELT, ta nạp dữ liệu thô vào kho trước, rồi biến đổi ngay trong kho bằng chính sức mạnh của nó. dbt sinh ra để làm chữ "T" của ELT.
Model — viên gạch cơ bản
Đơn vị làm việc của dbt là model. Một model đơn giản là một file .sql chứa đúng một câu lệnh SELECT. Bạn không cần viết CREATE TABLE hay INSERT — bạn chỉ mô tả "kết quả tôi muốn trông như thế nào", và dbt lo phần còn lại: nó sẽ tự bọc câu SELECT của bạn thành CREATE TABLE AS ... hoặc CREATE VIEW AS ... khi chạy.
Ví dụ một file khach_hang_sach.sql:
SELECT
customer_id,
LOWER(TRIM(email)) AS email,
created_at::date AS ngay_dang_ky
FROM {{ source('shop', 'raw_customers') }}
WHERE email IS NOT NULL
Ref và source — chất keo kết nối
Hai hàm quan trọng nhất trong dbt là ref() và source().
source()khai báo một bảng thô do hệ thống bên ngoài nạp vào (ví dụ dữ liệu từ đơn hàng do Fivetran đồng bộ).ref()tham chiếu đến một model dbt khác.
{{ ref('khach_hang_sach') }}. Nhờ đó dbt tự hiểu thứ tự phụ thuộc giữa các bảng: model A cần B, B cần C, nên phải chạy C → B → A. dbt vẽ ra một DAG (đồ thị phụ thuộc có hướng) và chạy đúng thứ tự, tự động. Bạn không bao giờ phải nhớ "phải chạy bảng nào trước".Vì sao dbt thay đổi cuộc chơi
Có ba lý do chính khiến dbt trở thành tiêu chuẩn:
- SQL, không cần ETL tool phức tạp. Analyst chỉ cần biết SQL là làm chủ được transformation. Không cần học Spark, Java hay công cụ kéo-thả đắt tiền.
- Version control (Git) cho data model. Mọi model là file text, được quản lý trong Git. Bạn thấy được ai đổi gì, khi nào, vì sao; có thể review qua pull request, rollback khi sai. Data model được đối xử như code — đây là bước nhảy vọt về kỷ luật.
- Testing. dbt cho phép khai báo test ngay cạnh model: cột này có được phép null không? Giá trị có unique không? Khóa ngoại có khớp bảng cha không? Trước khi số liệu chạy ra dashboard, dbt kiểm tra tự động và báo động nếu dữ liệu bẩn.
Kiến trúc phân tầng: staging → intermediate → marts
Một dự án dbt trưởng thành thường tổ chức model thành ba tầng:
- Staging: làm sạch nhẹ từng nguồn (đổi tên cột, ép kiểu, chuẩn hóa). Mỗi bảng thô một staging model.
- Intermediate: xử lý logic nghiệp vụ trung gian, kết hợp nhiều staging.
- Marts: bảng cuối cùng phục vụ báo cáo, thường theo chủ đề nghiệp vụ (doanh thu, khách hàng, marketing).
Tình huống thực tế
Ví dụ 1 — Sàn TMĐT giả định "ChợViệt" và bài toán "ba con số doanh thu"
ChợViệt là một sàn thương mại điện tử tầm trung ở TP.HCM, khoảng 40 nhân sự, dữ liệu nằm trong BigQuery. Trước khi dùng dbt, mỗi phòng ban tự viết truy vấn: phòng Tài chính báo doanh thu tháng 3 là 12,4 tỷ, phòng Marketing báo 13,1 tỷ, còn CEO nhìn dashboard thấy 11,9 tỷ. Nguyên nhân: mỗi người định nghĩa "doanh thu" khác nhau — người trừ đơn hoàn, người không; người tính theo ngày đặt hàng, người theo ngày giao thành công.
Đội data (chỉ 2 người) triển khai dbt trong 6 tuần. Họ tạo một model duy nhất fct_doanh_thu, đóng gói đúng một định nghĩa doanh thu đã được ban lãnh đạo duyệt: tính theo ngày giao thành công, đã trừ hoàn tiền, quy về VND. Mọi dashboard từ đó chỉ được phép ref bảng này.
Bài học rút ra: giá trị lớn nhất của dbt ban đầu không phải là kỹ thuật, mà là một nguồn sự thật duy nhất (single source of truth). Khi logic nghiệp vụ được viết một lần, ở một nơi, có Git kiểm soát, thì "chiến tranh con số" giữa các phòng ban chấm dứt.
Ví dụ 2 — Startup fintech Đông Nam Á và sức mạnh của testing
Một startup ví điện tử ở khu vực (giả định tên "PayNow") có khoảng 3 triệu người dùng. Một sáng, đội tăng trưởng phát hiện báo cáo số giao dịch tăng vọt 30% chỉ sau một đêm — nhưng thực tế không có chiến dịch nào. Điều tra ra: nhà cung cấp dữ liệu đầu vào đổi định dạng, khiến một số giao dịch bị đếm trùng hai lần.
Sau sự cố, họ thêm test dbt vào model giao dịch: một test unique trên transaction_id, và một test tùy chỉnh kiểm tra rằng số giao dịch mỗi ngày không lệch quá 3 lần độ lệch chuẩn so với trung bình 30 ngày. Vài tuần sau, cùng loại lỗi từ nhà cung cấp tái diễn — nhưng lần này pipeline dbt thất bại ngay ở bước test, chặn dữ liệu bẩn trước khi nó chạm dashboard. Cảnh báo bắn về Slack lúc 2 giờ sáng, và không con số sai nào lọt ra ngoài.
Bài học rút ra: test trong dbt không phải thứ trang trí. Nó là "hàng rào" chặn dữ liệu bẩn. Chi phí thêm vài test nhỏ rẻ hơn rất nhiều so với việc lãnh đạo ra quyết định sai vì số liệu lỗi.
Ví dụ 3 — Đội marketing agency và tài liệu tự sinh
Một agency ở Hà Nội quản lý dữ liệu quảng cáo cho 20 khách hàng, với hơn 150 bảng dữ liệu. Vấn đề kinh điển: người phân tích cũ nghỉ việc, và không ai hiểu bảng mart_roas_final_v3 được tính từ đâu, cột blended_cost nghĩa là gì.
Khi chuyển sang dbt, họ tận dụng tính năng dbt docs: mỗi cột được mô tả ngay trong file cấu hình .yml, và dbt tự sinh ra một trang web tài liệu, kèm sơ đồ lineage (dòng chảy dữ liệu) cho thấy bảng nào bắt nguồn từ bảng nào. Người mới vào chỉ cần mở docs là hiểu toàn bộ hệ thống trong nửa ngày, thay vì mất hai tuần dò hỏi.
Bài học rút ra: tài liệu và lineage tự sinh biến kiến thức "nằm trong đầu một người" thành tài sản của cả tổ chức — cực kỳ quan trọng khi đội ngũ thay đổi nhân sự.
Hướng dẫn từng bước
Đây là lộ trình để bắt đầu một dự án dbt thực tế:
Bước 1 — Cài đặt và kết nối. Chọn giữa dbt Core (mã nguồn mở, miễn phí, chạy dòng lệnh) hoặc dbt Cloud (có giao diện web, scheduler, phù hợp đội chưa mạnh về hạ tầng). Cài dbt-bigquery hoặc dbt-snowflake tùy warehouse. Cấu hình file profiles.yml chứa thông tin kết nối tới kho dữ liệu.
Bước 2 — Khởi tạo dự án. Chạy dbt init ten_du_an. dbt tạo sẵn cấu trúc thư mục chuẩn: models/, tests/, macros/, và file dbt_project.yml.
Bước 3 — Khai báo source. Trong một file .yml, khai báo các bảng thô đã có sẵn trong kho, đặt tên logic cho chúng để dùng qua source().
Bước 4 — Viết staging model. Tạo một staging model cho mỗi bảng nguồn: đổi tên cột về quy ước chung, ép kiểu, chuẩn hóa (ví dụ email viết thường). Chỉ làm sạch, chưa tính toán nghiệp vụ.
Bước 5 — Xây model nghiệp vụ. Dùng ref() để nối các staging model lại, tính các chỉ số nghiệp vụ (doanh thu, số khách hoạt động). Đây là nơi logic quan trọng của tổ chức được đóng gói.
Bước 6 — Chạy và kiểm thử. Chạy dbt run để dbt xây tất cả bảng theo đúng DAG. Sau đó dbt test để chạy toàn bộ test đã khai báo. Cuối cùng dbt docs generate && dbt docs serve để xem tài liệu và lineage.
Bước 7 — Đưa vào Git và lên lịch. Commit toàn bộ dự án vào Git, review qua pull request. Lên lịch chạy tự động hằng ngày (qua dbt Cloud hoặc công cụ điều phối như Airflow).
Lỗi thường gặp & mẹo
- Nhồi mọi logic vào một model khổng lồ. Một model 400 dòng SQL lồng nhau là ác mộng bảo trì. Hãy chia nhỏ theo tầng staging → intermediate → marts.
- Gõ cứng tên bảng thay vì dùng
ref/source. Đây là lỗi phá vỡ toàn bộ giá trị của dbt: DAG không còn đúng, lineage sai, và khi đổi môi trường (dev/prod) mọi thứ vỡ. Luôn dùngref()vàsource().
- Không viết test. Rất nhiều đội dùng dbt chỉ để chạy SQL cho tiện mà bỏ qua test — đánh mất một nửa giá trị. Tối thiểu hãy thêm
uniquevànot_nullcho các khóa chính.
- Lạm dụng model kiểu
tablekhi không cần. Model có thể materialize thànhview(nhẹ, luôn mới) hoặctable(nặng hơn nhưng truy vấn nhanh). Bảng nhỏ, ít dùng nên đểviewđể tiết kiệm chi phí lưu trữ và tính toán.
- Mẹo — dùng
incrementalcho bảng lớn. Với bảng hàng trăm triệu dòng, đừng dựng lại toàn bộ mỗi lần. Materialize kiểuincrementalchỉ xử lý dữ liệu mới, tiết kiệm rất nhiều chi phí warehouse.
- Mẹo — đặt tên nhất quán. Quy ước như
stg_,int_,fct_,dim_giúp cả đội đọc code hiểu ngay vai trò của mỗi bảng.
Bài tập thực hành
Giả sử bạn có hai bảng thô trong warehouse: raw_orders (đơn hàng, gồm order_id, customer_id, amount, status, created_at) và raw_customers (customer_id, email, city).
- Khai báo hai bảng này làm
sourcetrong một file.yml. - Viết hai staging model
stg_ordersvàstg_customers: ép kiểu ngày, chuẩn hóa email về chữ thường, đổi tên cột theo quy ước riêng của bạn. - Viết một mart model
fct_doanh_thu_theo_thanh_phodùngref()để nối hai bảng, chỉ tính các đơn cóstatus = 'completed', tổng doanh thu theo từng thành phố. - Thêm test:
uniquevànot_nullchoorder_idtrongstg_orders; testnot_nullcho cột doanh thu ở mart. - Vẽ tay sơ đồ DAG của dự án: nguồn → staging → mart. Xác định model nào chạy trước, model nào chạy sau và giải thích vì sao dbt biết được thứ tự đó.
raw_orders đổi tên một cột, bạn cần sửa ở mấy chỗ? (Gợi ý: chỉ ở staging — đó chính là sức mạnh của phân tầng.)Tóm tắt
dbt là công cụ đảm nhận chữ "T" trong quy trình dữ liệu hiện đại: nó không di chuyển hay tự tính dữ liệu, mà điều phối các câu SQL để warehouse thực thi theo đúng thứ tự. Ba trụ cột giá trị của dbt là: viết transformation chỉ bằng SQL (không cần ETL tool phức tạp), quản lý data model bằng Git như code, và kiểm thử tự động để chặn dữ liệu bẩn. Nhờ ref() và source(), dbt tự dựng DAG phụ thuộc, còn kiến trúc phân tầng staging → intermediate → marts giữ cho dự án sạch và dễ bảo trì. Như các ví dụ đã thấy, giá trị thực sự không chỉ nằm ở kỹ thuật, mà ở việc tạo ra một nguồn sự thật duy nhất, ngăn "chiến tranh con số", và biến kiến thức thành tài sản chung của tổ chức. Khi đã có các bảng sạch và đáng tin từ dbt, bạn đã sẵn sàng đưa chúng lên các công cụ BI ở bài tiếp theo.