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

Tầng staging và mart

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

  • Ba tầng model trong một project dbt và việc gì thuộc tầng nào.
  • Quy ước đặt tên stg_, int_, fct_, dim_.
  • Vì sao staging không được join và mart không được đọc thẳng nguồn.
  • Chọn materialization mặc định cho từng tầng.
  • Nhận ra dấu hiệu logic bị lặp giữa các mart.

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

Một project dbt lớn thường có hàng trăm model. Nếu ai cũng viết model theo cách riêng, sau sáu tháng không ai dám sửa gì. Tầng model là quy ước chung để mỗi file có một chỗ đứng rõ ràng.

TầngTiền tốLàm gìKhông làm gì
Stagingstg_Đổi tên cột, ép kiểu, lọc bản ghi rác, giải mã giá trịJoin, tính toán kinh doanh, gộp nhiều nguồn
Intermediateint_Join, gộp, tính bước trung gian phức tạpĐược người dùng cuối đọc trực tiếp
Martfct_, dim_Bảng sự kiện và bảng chiều phục vụ báo cáoĐọc thẳng bảng nguồn thô

Quy tắc quan trọng nhất: staging ánh xạ 1–1 với bảng nguồn. Mỗi bảng nguồn có đúng một model staging. Nhờ vậy khi nguồn đổi tên cột, bạn sửa đúng một file.

Tầng mart chia hai loại:

  • Fact (fct_): một dòng là một sự kiện — một đơn hàng, một lần thanh toán, một phiên truy cập. Có khoá ngoại và số đo.
  • Dimension (dim_): một dòng là một thực thể — một khách hàng, một sản phẩm, một cửa hàng. Có thuộc tính mô tả.

Ví dụ chạy được

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

code
models/
  staging/
    sources.yml
    stg_orders.sql
    stg_customers.sql
    stg_payments.sql
  intermediate/
    int_orders_enriched.sql
  marts/
    fct_orders.sql
    dim_customers.sql
    schema.yml

Tầng staging — chỉ làm sạch:

code
-- models/staging/stg_orders.sql
select
    id                              as order_id,
    customer_id,
    cast(created_at as date)        as order_date,
    lower(status)                   as status,
    amount_cents / 100.0            as amount,
    coalesce(discount_cents, 0)/100.0 as discount
from {{ source('raw', 'orders') }}
where id is not null

Tầng intermediate — nơi được phép join:

code
-- models/intermediate/int_orders_enriched.sql
select
    o.order_id,
    o.order_date,
    o.customer_id,
    c.segment,
    c.region,
    o.amount - o.discount as net_amount
from {{ ref('stg_orders') }} o
left join {{ ref('stg_customers') }} c using (customer_id)

Tầng mart — tổng hợp cho báo cáo:

code
-- models/marts/fct_orders.sql
select
    order_date,
    segment,
    region,
    count(*)          as orders,
    sum(net_amount)   as revenue
from {{ ref('int_orders_enriched') }}
where status in ('paid', 'shipped')
group by 1, 2, 3

Cấu hình materialization theo tầng trong dbt_project.yml:

code
models:
  dbt_shop:
    staging:
      +materialized: view
    intermediate:
      +materialized: view
    marts:
      +materialized: table

Với 1.000.000 đơn hàng, staging dạng view tốn 0 giây lưu trữ và luôn phản ánh nguồn mới nhất. Mart dạng table tốn khoảng 40 giây build mỗi lần chạy nhưng dashboard chỉ đọc một bảng đã gộp sẵn, thay vì join lại 1.000.000 dòng mỗi lần tải trang.

Vì sao phải tách tầng

Tái sử dụng. Nếu ba mart đều cần "đơn hàng đã trừ giảm giá", logic đó nằm một lần ở int_orders_enriched. Khi quy tắc giảm giá đổi, sửa một chỗ.

Cô lập thay đổi. Nguồn đổi tên amount_cents thành amount_minor, chỉ stg_orders phải sửa. Mọi mart phía sau không biết gì.

Kiểm thử đúng chỗ. Test kỹ thuật (unique, not_null, relationships) đặt ở staging. Test nghiệp vụ (tổng khớp, không âm, không vượt ngưỡng) đặt ở mart.

Đọc được đồ thị. Nhìn lineage thấy ngay dữ liệu đi từ nguồn nào, qua bước nào, tới báo cáo nào.

Dấu hiệu thiết kế sai

Dấu hiệuVấn đềCách sửa
stg_ có joinTrộn hai trách nhiệmChuyển join sang int_
Ba mart cùng viết lại một case whenLogic lặpĐưa lên int_
Mart đọc {{ source(...) }}Bỏ qua lớp làm sạchĐọc qua stg_
Một mart dài 400 dòngKhông tách bướcChia thành hai int_
stg_ lọc theo điều kiện kinh doanhStaging không còn 1–1Chuyển bộ lọc sang mart

Thực hành

  1. Liệt kê các bảng nguồn của bạn và tạo một stg_ cho mỗi bảng.
  2. Chuyển một phép join đang nằm trong mart xuống int_.
  3. Đặt materialization view cho staging, table cho mart trong dbt_project.yml.
  4. Chạy dbt build --select staging rồi dbt build --select marts.
  5. Mở dbt docs serve, xem lineage và đếm số tầng từ nguồn tới một mart.

Lỗi thường gặp

Triệu chứngNguyên nhânCách sửa
Sửa nguồn phải sửa 5 modelMart đọc thẳng sourceCho mart đọc qua stg_
Hai báo cáo ra số khác nhauLogic join lặp ở hai martGom vào một int_
Dashboard chậmMart để view trên nguồn lớnĐổi mart sang table
Dữ liệu mart trễStaging là table build theo lịchĐổi staging sang view
Không tìm được nguồn của cộtTầng trung gian đặt tên khác nhauGiữ tên cột gốc ở staging

Tóm tắt

  • Ba tầng: staging làm sạch, intermediate join và tính toán, mart phục vụ báo cáo.
  • Staging 1–1 với bảng nguồn, không join, không lọc nghiệp vụ.
  • Fact là sự kiện, dimension là thực thể.
  • Materialization mặc định: staging view, mart table.
  • Logic lặp giữa các mart là dấu hiệu cần thêm tầng intermediate.

Use ← → to move between lessons