










这是 FAQ 系列第三篇,聚焦 dbt 的日常运维和实操问题:run 与 test 的关系、依赖查询、并发配置、SQL Server 特有差异、版本回滚等。都是项目跑起来之后一定会碰到的问题。
business_db(SQL Server 业务库,含 customers / orders / products 三张表)threads: 1 串行执行,dev 环境直接连 SQL Server 实例答:run 负责"建表/装数据",test 负责"查数据对不对",两者是独立的命令,但推荐一起用。
| 命令 | 做什么 | 会不会改表 |
|---|---|---|
dbt run |
编译模型 SQL,在数据库里创建/更新表和视图 | ✅ 会改 |
dbt test |
运行测试断言(schema test + data test),输出通过/失败 | ❌ 只读 |
dbt run → dbt test
先跑 run,再跑 test。原因很简单:测试要检查表的数据,如果表还不存在或者数据是旧的,测试就没意义了。
dbt build
dbt build 会自动按依赖顺序执行:对每个模型,先 run 再 test,上游模型测试失败会阻断下游 run。
举个例子,执行 dbt build --select stg_customers+ 时:
① stg_customers → ② run stg_customers → ③ test stg_customers
│
测试通过 → 继续往下游跑
测试失败 → 下游直接跳过
这比手动 dbt run && dbt test 更智能——它能在 DAG 层面做到"上游有问题,下游不浪费时间"。
dbt run --select 模型名,快速迭代dbt build --select +模型名+,确保上下游都没问题dbt build 全量跑,测试失败告警答:测试失败只是"报告问题",不会自动回滚或修改数据。已经跑好的表该什么样还是什么样。
dbt run = 厨师炒菜(改变菜品)
dbt test = 质检员尝菜(只尝不动)
菜炒咸了 → 质检员说"不合格" → 但菜还是那盘咸的菜
→ 厨师要不要重做,是人决定的
| 场景 | 行为 | 结果 |
|---|---|---|
dbt test 单独跑 |
报告失败,表不动 | 数据是旧的/错的 |
dbt run && dbt test |
run 成功了,test 失败 | 新数据已经写进去了,但质量不达标 |
dbt build |
上游模型测试失败 → 下游模型不跑 | 下游保持旧数据,上游已经被改了 |
dbt run --select 模型名dbt test --select 模型名注意:
dbt build虽然能阻断下游,但不会回滚当前模型。比如stg_customersrun 成功了但 test 失败,stg_customers的表已经是新数据了,只是下游不会接着跑。
答:主要有三种方式:dbt ls 命令行、dbt docs 可视化图、以及直接看 SQL 里的 ref()。
# 看 hub_customer 上游依赖了谁(左边 + 号)
dbt ls --select +hub_customer
# 看 hub_customer 被谁依赖(右边 + 号)
dbt ls --select hub_customer+
# 上下游一起看
dbt ls --select +hub_customer+
输出大概长这样:
model.dbt_sqldv.stg_customers
model.dbt_sqldv.hub_customer
model.dbt_sqldv.sat_customer
model.dbt_sqldv.dim_customer
model.dbt_sqldv.dws_order_wide
dbt docs generate # 生成文档
dbt docs serve # 启动本地网页查看
打开后在 DAG 图里可以:
在模型文件里搜 ref() 和 source():
-- sat_customer.sql 里有这两个引用
FROM {{ ref('stg_customers') }}
-- 还有 JOIN hub 的逻辑...
直接看代码能知道具体依赖了哪些字段,比命令行更细。
| 场景 | 命令 |
|---|---|
改了 stg_customers,想知道哪些下游要跟着改 |
dbt ls --select stg_customers+ |
dim_customer 跑失败了,想知道上游有哪些 |
dbt ls --select +dim_customer |
| 想确认某个模型在 DAG 第几层 | dbt ls --output json --select dim_customer | jq '.depends_on' |
答:适当调大没问题,能加快速度;但调得过大确实可能出问题。
threads 是 dbt 的并发数,控制同一时刻最多有几个模型在跑。
你们当前 profiles.yml 里是:
dev:
threads: 1 # 串行,一个跑完再跑下一个
dbt 同一批次(同一层)内的模型没有依赖关系,可以并行跑。比如 staging 层有 3 个模型:
threads: 1 → 一个一个跑,总时间 = 3 个模型时间之和threads: 3 → 三个一起跑,总时间 ≈ 最慢那个的时间对于你们项目,threads 调到 3 或 4 比较合理——每层最多也就 4 个模型(core 第 3 批)。
dbt run --select 模型名 单独跑失败的那个| 环境 | 推荐 threads | 原因 |
|---|---|---|
| 本地开发 | 2-4 | 快一点,同时不压爆库 |
| 测试环境 | 4-8 | 可以大胆一点 |
| 生产环境 | 4-16 | 看数据库承载能力,慢慢往上加 |
经验法则:从 2 开始,每次翻倍,观察数据库 CPU 和 IO。到了瓶颈就往回退一档。
答:dbt 的核心用法(模型、ref、test、deps)都一样,但在方言、物化方式、驱动、权限上有不少差异。
不同数据库的 SQL 语法有差异,dbt adapter 会处理大部分,但写复杂 SQL 时要注意:
| 功能 | SQL Server | BigQuery / Snowflake |
|---|---|---|
| 日期转换 | CONVERT(VARCHAR, date_col, 126) |
FORMAT_DATE() / TO_VARCHAR() |
| 字符串拼接 | 'a' + 'b' |
CONCAT('a', 'b') |
| 分页 | OFFSET ... ROWS FETCH NEXT ... |
LIMIT ... OFFSET ... |
| 窗口函数 | 支持 | 支持(语法略有差异) |
| 递归 CTE | 支持 | 支持 |
你们项目里的 macro(比如 generate_hashkey)就是针对 SQL Server 写的,换到另一个数据库不能直接用。
table 重建非常快(列式存储 + 分布式计算),很多项目全用 table 也不慢。incremental。你们 core 层全部用 incremental,很大程度上也是 SQL Server 环境下的务实选择。
你们 profiles.yml 里配置了:
driver: "ODBC Driver 18 for SQL Server"
encrypt: false
trust_server_certificate: true
这些都是 SQL Server 特有的配置。
dbt 提供了很多全局 macro(比如 dbt_utils 包),大部分跨数据库兼容,但少数不行。自己写 macro 时如果用了数据库特有的函数,就只能在对应数据库上跑。
dbt 项目本身不管理数据库权限(那是 DBA 的活),但你得有对应的建表、读写权限才能跑。
这也导致使用习惯不一样:云数仓会更注意节省计算资源,SQL Server 反而可以放开了跑。
好消息是:90% 的 dbt 用法是通用的。模型写法、ref/source、测试、依赖管理、文档——这些在哪个数据库上都一样。真正需要注意的就是你写的 SQL 本身和数据库特有函数。
答:dbt 本身不提供"一键回滚",回滚主要靠 Git 版本控制 + 全量重建。
dbt 是一个转换工具,不是数据库的版本管理系统。它的理念是:
"代码是唯一真相来源。只要代码对,重新跑一遍就能得到正确的数据表。"
所以回滚的思路是:回滚代码 → 重跑模型。
# 1. 用 git 回退代码
git log --oneline # 找到要回退的 commit
git checkout <commit-hash> -- models/ # 只回退模型文件
# 2. 重跑受影响的模型
dbt run --select 模型名
# 或者全量重建
dbt run --full-refresh --select 模型名
# 强制全量重建,把表干掉重跑
dbt run --full-refresh --select sat_customer
这是最常用的"回滚"方式——不是回退到旧数据,而是用正确的逻辑从头重建。
git checkout <commit-hash> # 整个项目回退
dbt run --full-refresh # 全量重建
这里有个容易踩的坑:增量模型的代码回退了,数据不会自动回退。
比如:
v1 版本跑了 100 条数据 → 表中有 100 条
v2 版本加了逻辑,又增量跑了 50 条 → 表中有 150 条
代码回退到 v1 → 再增量跑 → 表中还是 150 条(不会删掉那 50 条)
解决办法:回退代码后,用 --full-refresh 全量重建一次。
--full-refresh,纠正各种数据偏差dbt snapshot 记录历史状态,出问题有据可查dbt 没有"撤销键",但 Git +
--full-refresh就是它的版本回滚方案。
这 6 个问题,都是 dbt 项目从"跑起来"到"稳定运行"必然会遇到的运维话题:
运维意识到位了,dbt 项目才能从"个人学习项目"变成"生产级数据管道"。
记录时间:2026-08-05
环境:dbt + SQL Server,Data Vault 核心层 + 星型模型集市层
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。