構建 dbt 模型 是做什麼的?
何時使用
- 在 dbt 專案中建立或重構
.sql模型。 - 決定物化策略(view / table / incremental / ephemeral)。
- 組織分層結構(staging → intermediate → marts)。
- 為大型、持續增長的資料表撰寫增量模型。
- 請勿用於測試撰寫(請使用
testing-dbt-projects)或執行失敗處理(請使用debugging-dbt-runs)。
工作流程
- [ ] 將模型放置於正確的層級(staging/intermediate/marts)
- [ ] 僅透過 ref()/source() 引用上游資料 — 絕不硬編碼名稱
- [ ] 根據大小與刷新需求選擇物化策略
- [ ] 對於增量模型,設定 unique_key + is_incremental() 過濾器
- [ ] 在 schema.yml 中新增測試條目
- 分層。
staging/= 每個來源資料表一個模型,進行輕量的重新命名與型別轉換,物化為 view。intermediate/= 可重複使用的商業邏輯。marts/= 供 BI 使用的最終維度模型,物化為 table。 - 正確引用。 使用
{{ ref('stg_orders') }}與{{ source('shop', 'orders') }},讓 dbt 建立 DAG 並管理環境。絕不直接撰寫原始 schema.table。 - 選擇物化策略: view(便宜、永遠最新、適合小資料)、table(讀取快速、每次執行重建)、incremental(大型附加/更新資料表)、ephemeral(內嵌 CTE,不建立物件)。
- 增量模型 只處理新增或變更的資料列。
模式
Staging 模型 — 每個來源一個,輕量且一致:
-- models/staging/shop/stg_orders.sql
with source as (select * from {{ source('shop', 'orders') }})
select
order_id,
customer_id,
cast(order_ts as timestamp) as ordered_at,
round(amount_cents / 100.0, 2) as amount
from source
增量模型 — 過濾新增資料列並設定冪等合併鍵:
{{ config(materialized='incremental', unique_key='order_id',
incremental_strategy='merge') }}
select * from {{ ref('stg_orders') }}
{% if is_incremental() %}
-- 只載入比現有資料更新的資料列,並加入回溯以處理延遲到達的資料
where ordered_at >= (select coalesce(max(ordered_at), '1900-01-01') from {{ this }})
- interval '3 days'
{% endif %}
unique_key 加上 merge 使重新執行具有冪等性;回溯則能捕捉延遲到達的資料列。在 BigQuery/Spark 上,建議對日期分割區使用 insert_overwrite。
常見陷阱
- 使用硬編碼的資料表名稱 而非
ref()/source()— 會破壞 DAG、血緣與環境切換。 - 增量模型缺少
unique_key— 重新執行時會附加重複資料。 - 使用
max(id)增量過濾器但無回溯 — 會默默丟失延遲到達的資料。 - 在 staging 層中加入商業邏輯 — 保持 staging 輕量;連線與聚合應歸屬於 intermediate/marts。
- 所有模型都物化為
table— 浪費倉儲時間;小/便宜模型應使用 view,大型模型則用 incremental。 - 單一巨型模型 — 應拆分為 intermediate 步驟以提高可測試性與可重用性。