构建 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/= 每个源表一个模型,进行轻量重命名和类型转换,物化为视图。intermediate/= 可复用的业务逻辑。marts/= 最终维度模型,供 BI 使用,物化为表。 - 正确引用。 使用
{{ 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——浪费仓库时间;小/廉价模型使用视图,大型模型使用增量。 - 一个巨型模型——拆分为中间步骤以提高可测试性和复用性。