关于 working-with-dbt-mesh
面向管理 dbt Mesh 项目模型治理与跨项目依赖的技能,适用于分析工程师。它强调在变更前评估影响,并合理使用模型版本、访问控制和契约。
主要功能
- 01配置并检查跨项目引用
- 02评估模型破坏性变更影响
- 03应用模型契约与访问控制
- 04管理模型版本和迁移
适用场景
- 01变更共享模型前检查依赖
- 02配置可供跨项目引用的公开模型
- 03规划列改名或删除的迁移
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ dbt-labs/ dbt-agent-skills --skill working-with-dbt-mesh安装后在 Claude Code 中输入/working-with-dbt-mesh确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/cross-project-collaboration.mdgroups-and-access.mdmodel-contracts.mdmodel-versions.md详细介绍
使用 dbt Mesh
核心原则: 在 mesh 项目中,上游数据通过 ref() 获取,而不是通过 source()。所有跨项目引用都必须包含项目名称。如有疑问,请先查看 dependencies.yml。
适用场景
- 对模型进行可能造成破坏性影响的更改,例如重命名、移除或更改列的类型,尤其是在其他模型、exposure 或 BI 工具依赖该模型时。 更改前评估影响范围,并优先使用模型版本,而不是直接修改现有模型。
- 为模型设置版本(
versions:、latest_version、latest_version_pointer、deprecation_date)——这适用于单项目,并非仅适用于多项目设置 - 在引用其他 dbt 项目中模型的 dbt 项目中工作
- 当多个上游项目有名称相似的模型(例如多个
stg_模型)时消除歧义 - 添加模型契约、访问修饰符或组
- 使用
dependencies.yml设置跨项目引用 - 将单体 dbt 项目拆分为多个 mesh 项目
不要用于:
- 常规模型构建或调试(使用
using-dbt-for-analytics-engineering技能) - 模型单元测试(使用
adding-dbt-unit-test技能) - 语义层工作(使用
building-dbt-semantic-layer技能)
首先:了解多项目设置
在使用 dbt Mesh 的项目中编写或修改任何 SQL 之前,请执行以下步骤:
1. 查看 dependencies.yml
项目根目录下的此文件会列出已有的上游项目:
# dependencies.yml
projects:
- name: core_platform
- name: marketing_platform
如果此文件中有 projects: 键,说明你处于多项目 mesh 设置中。引用这些上游项目中的任何模型时,都必须使用跨项目 ref()。
2. 了解上游数据如何进入此项目
在 mesh 设置中,上游项目模型取代了原本可能使用的 sources:
| 替代方式 | Mesh 多项目 |
|---|---|
{{ source('stripe', 'payments') }} | {{ ref('core_platform', 'stg_payments') }} |
| 数据来自原始数据库表 | 数据来自另一个 dbt 项目的公共模型 |
在 sources.yml 中定义 | 在 dependencies.yml 中声明 |
上游项目已经对原始数据进行了暂存和转换。你的项目应基于其公共模型构建,而不是基于其原始 sources。
3. 消除名称相似的模型之间的歧义
当多个上游项目有同名模型时(例如 core_platform 和 marketing_platform 中都有 stg_customers),必须使用双参数 ref():
-- Correct: explicit project name, no ambiguity
select * from {{ ref('core_platform', 'stg_customers') }}
select * from {{ ref('marketing_platform', 'stg_customers') }}
-- WRONG: dbt cannot determine which project's stg_customers you mean
select * from {{ ref('stg_customers') }}
4. 检查代码库中的现有模式
编写新 SQL 之前:
- 搜索现有的双参数
ref()调用,了解已使用的上游项目和模型 - 查看上游项目的 YAML,查找设置了
access: public的模型——只有这些模型可以跨项目引用 ref()的第一个参数必须与上游项目dbt_project.yml中的name字段完全一致(区分大小写)
5. 了解可以和不可以引用的对象
| 上游模型访问权限 | 能否跨项目使用 ref() 引用? |
|---|---|
access: public | 可以 |
access: protected(默认) | 不可以——只能在同一项目内使用 |
access: private | 不可以——只能在同一组内使用 |
如果你需要的模型不是 public,请与上游团队协调以扩大其访问范围。
跨项目 Refs 需要 dbt Cloud Enterprise
跨项目 ref() 和 dependencies.yml 中的 projects: 键仅适用于 dbt Cloud Enterprise 或 Enterprise+ 计划。在设置任何跨项目协作之前,请确认计划是否符合要求:
- 如果
dependencies.yml已包含projects:键,且项目正在使用跨项目 refs — Enterprise 已就绪。继续操作。 - 否则 — 在向
dependencies.yml添加projects:或编写新的双参数ref()调用之前,请用户确认他们使用的是 dbt Cloud Enterprise 或 Enterprise+。
如果用户无法确认计划级别,或确认他们使用的计划低于 Enterprise,请勿设置跨项目 refs。说明此功能需要升级到 Enterprise 或 Enterprise+,并建议他们改用项目内治理功能(groups、access modifiers、contracts)。
跨项目 ref() 语法
-- Reference an upstream model (latest version)
select * from {{ ref('upstream_project', 'model_name') }}
-- Reference a specific version
select * from {{ ref('upstream_project', 'model_name', v=2) }}
有关完整的跨项目设置详情(dependencies.yml、前提条件、编排),请参阅 references/cross-project-collaboration.md。
治理功能
dbt Mesh 包含四项治理功能。这些功能彼此独立,可逐步采用:
| 功能 | 用途 | 关键配置 | 参考文档 |
|---|---|---|---|
| 模型契约 | 在构建时保证列名、类型和约束 | contract: {enforced: true} | references/model-contracts.md |
| Groups | 按团队/领域归属组织模型 | group: finance | references/groups-and-access.md |
| 访问修饰符 | 控制哪些模型可以 ref 你的模型 | access: public / protected / private | references/groups-and-access.md |
| 模型版本 | 通过迁移窗口管理破坏性变更 | 使用 latest_version: 和 latest_version_pointer 的 versions:(v1.12+) | references/model-versions.md |
YAML 放置规则
在模型属性 YAML 文件中,access、group 和 contract 都是配置项,必须始终嵌套在 config: 键下,绝不能放在模型属性顶层。在顶层放置这些配置项可能在 dbt Core 中看似可行,但会导致 dbt Fusion 引擎出现解析错误。
# ✅ CORRECT — all governance configs under `config:`
models:
- name: fct_orders
config:
group: finance
access: public
contract:
enforced: true
columns:
- name: order_id
data_type: int
# ❌ WRONG — governance configs as top-level properties (breaks Fusion)
models:
- name: fct_orders
access: public # WRONG — not under config:
group: finance # WRONG — not under config:
contract: # WRONG — not under config:
enforced: true
columns:
- name: order_id
data_type: int
此规则仅适用于属性 YAML 文件。在 dbt_project.yml 中,使用 + 前缀进行目录级赋值(例如 +group: finance、+access: private)。在 SQL 文件中,使用 {{ config(access='public', group='finance') }}。
采用顺序
1. Groups & Access → 2. Contracts → 3. Versions → 4. Cross-Project Refs
(organize teams) (lock shapes) (manage changes) (split projects)
- Groups 和 Access — 无需更改 schema,从这里开始
- Contracts — 需要在 YAML 中声明每一列及其数据类型
- Versions — 当模型必须引入破坏性变更,且需要给使用者留出迁移时间时,需要使用此功能(建议同时使用强制执行的契约,但并非必需)
- 跨项目 Refs — 需要 dbt Cloud Enterprise 或 Enterprise+,以及成功运行的上游生产作业。如果无法确认计划级别为 Enterprise 或更高级别,请勿设置跨项目 refs。
契约与测试
| 契约 | 数据测试 | |
|---|---|---|
| 何时 | 构建时(预检) | 构建后(后检) |
| 内容 | 列名、数据类型、约束 | 数据质量、业务规则 |
| 失败结果 | 模型不会物化 | 模型存在,但测试失败 |
| 适用场景 | 为下游使用者保证结构 | 内容验证和异常检测 |
契约会在测试运行之前强制执行。如果契约失败,模型不会构建,也不会执行任何测试。
决策框架
这个模型应该设置契约吗?
适合设置契约的情况:
- 模型的
access: public(尤其是被其他项目引用时) - 其他团队依赖此模型架构的稳定性
- 模型为某个对外提供的数据对象提供数据(仪表板、ML 流水线、反向 ETL)
- 外部使用者(其他 dbt 项目、BI 仪表板、反向 ETL)会直接查询此表,且列重命名或移除会导致其出错
不要添加契约的情况:
- 暂存模型(
stg_*)——这些是内部实现细节,不是面向使用者的 API - 模型仍在演进——如果用户表示仍在迭代设计,建议等架构稳定后再设置契约
- 没有外部使用者——在没有跨项目引用、没有依赖此架构的 BI 工具、也没有对外提供的数据对象的单项目设置中,契约只会增加维护负担,并无实际收益。推荐契约前,先询问有哪些使用者。
- 动态列/透视列——使用
pivot()、unpivot()或动态生成列的模型并不适合设置契约,因为列清单并不固定,动态值一变,契约就会失效 - 临时模型——临时物化不支持契约
**如果用户要求为符合上述“不要添加”条件的模型设置契约,请建议不要这样做,并说明原因。**不要直接照办——用户可能没有意识到该模型不适合设置契约。请提出替代方案(例如,为暂存模型添加数据测试、等待架构稳定,或更改临时模型的物化方式)。
这个模型应该进行版本控制吗?
适合对模型进行版本控制的情况:
- 需要对使用者依赖的模型进行破坏性变更(移除列、重命名列或更改类型)——**无论是否启用了强制契约。**契约会让这类变更在构建时出错;没有契约时,变更会悄无声息地传递到下游模型和仪表板,因此迁移窗口更为重要。不要因为“没有契约”就放弃对破坏性变更进行版本控制。
- 使用者需要迁移窗口,以便在旧架构停用前完成迁移——**包括无法一次性更新的使用者:**其他团队的模型、对外提供的数据对象、仪表板,以及直接读取该表的 BI 工具。
不要对模型进行版本控制的情况:
- 对于增量变更(新增列)——这类变更不会造成破坏
- 对于错误修复——直接修复
- 不要为了“以防万一”而提前版本控制——只有在确实需要进行破坏性变更时才进行版本控制
- 只有在没有任何东西在 dbt 外部读取此模型时,才跳过版本控制——没有对外提供的数据对象、没有 BI 工具、没有其他项目。只要存在其中任何一种,就进行版本控制。
仅进行版本控制并不会创建迁移窗口——真正起作用的是 latest_version
添加新版本和将其提升为 latest_version 是两个独立的部署,中间必须隔开迁移窗口,绝不能在同一项变更中完成。 这是“安全”的版本化变更仍会导致仪表板故障的最常见原因。外部使用方(BI 工具、反向 ETL、仪表板)会按名称读取物理关系——几乎总是未加后缀的 model_name(指向最新版本的视图,或未进行版本控制时的普通模型)。该名称解析到 latest_version 指向的版本。因此:
- **部署 1 — 引入:添加具有新结构的新版本(例如
v2),但让latest_version保持指向旧版本(v1)。**这样,外部使用方仍可按名称读取旧列,并维护一个跟踪最新版本的规范(未加后缀)关系——由于latest_version仍指向v1,该规范关系会提供旧结构(机制见下表)。新结构可通过model_v2获取,供使用方进行迁移;你可控的内部使用方则可以通过固定到ref('model', v=2)提前迁移。 - **部署 2 — 提升(稍后):**只有在所有外部使用方确认已完成迁移后,才将
latest_version提升到2,并为v1设置deprecation_date。规范关系随后会自动改为指向新结构——无需重命名关系。
让规范关系继续提供旧结构——选择一种机制(绝不能同时使用两种):
| dbt 版本 | 默认机制 | 结果 |
|---|---|---|
| ≥ 1.12 / Fusion | 内置的 latest_version_pointer(目前处于测试阶段) | model_v1、model_v2、指针视图 model(3 个关系) |
| ≤ 1.11 | create_latest_version_view() 宏 + 项目 post-hook(dbt 官方推荐的模式) | model_v1、model_v2、规范视图 model(3 个关系) |
| 任一版本 — 仅作后备方案 | 使用 config.alias 将旧版本固定到未加后缀的名称 | 2 个关系;在部署 2 时需要手动移除别名并重新接线 |
始终优先使用适合当前版本的指针;仅当两种指针机制都不可用,或用户明确拒绝时,才使用 config.alias。绝不要在同一个名称上同时使用指针/视图和 alias(会导致冲突错误)。请参阅 model-versions.md。
提升 latest_version 本身就是针对未加后缀使用方的破坏性发布。 如果引入新版本时就将其设为最新版本(或在同一项变更中提升最新版本),迁移窗口就会变为零,仪表板会立即故障。新版本始终应从非最新版本开始。
部署 1 后,请验证迁移窗口确实已开启——使用方读取的关系仍必须返回旧列:
dbt show --inline "select <old_col> from {{ target.schema }}.<unsuffixed_relation>"
如果出现 column does not exist 错误,说明 latest_version 提升得太早,使用方已经故障。
此模型应设置什么访问级别?
Is it referenced cross-project?
└─ Yes → public (with contract recommended)
└─ No
Is it referenced outside its group?
└─ Yes → protected (default)
└─ No
Is it internal to a small team?
└─ Yes → private
└─ No → protected (default)
**最佳实践:**新模型默认设为 private,仅在需要时扩大访问范围。默认的 protected 较为宽松——请审慎设置。
常见错误
| 错误 | 错误原因 | 修正方法 |
|---|---|---|
在多项目设置中使用单参数 ref() | 含义不明确 — dbt 可能无法解析到预期的项目 | 跨项目引用时,始终使用 ref('project_name', 'model_name') |
使用 source() 获取上游项目数据 | 在 mesh 中,上游数据通过公共模型提供,而非原始源 | 改用 ref('upstream_project', 'model_name') |
未先读取 dependencies.yml | 你不会知道有哪些上游项目,也不知道它们的名称 | 编写跨项目 SQL 前,始终先读取 dependencies.yml |
将所有模型都设为 public | 会向其他项目暴露内部实现细节 | 仅将有意提供给其他团队使用的模型标记为 public |
| 跳过公共模型上的契约 | 架构发生变化时,下游使用者可能会在不知情的情况下受到影响 | 始终对 access: public 模型强制执行契约 |
| 为非破坏性变更进行版本控制 | 会造成不必要的维护负担和数仓成本 | 仅在发生破坏性变更(删除列、类型变更、重命名)时进行版本控制 |
将新版本直接设为 latest_version(或在同一变更中提升 latest) | 未加后缀的关系/指针会立即提供新结构,导致按名称读取它的 BI 工具和反向 ETL 中断 — 迁移窗口为零 | 引入新版本时,仍将 latest_version 指向旧版本;只有在使用者确认迁移后才提升版本 |
有合适的版本指针可用时,却使用 config.alias 保存未加后缀的名称 | 会缩减为 2 个关系,并在提升时迫使你手动取消别名并重新接线,而不是自动重新指向 | 默认使用 latest_version_pointer(≥1.12)或 create_latest_version_view post-hook(≤1.11);仅将 alias 用作备用方案 |
忘记 dependencies.yml | 未声明上游项目时,跨项目引用会失败 | 使用双参数 ref() 前,将上游项目添加到 dependencies.yml |
| 跨项目引用非公共模型 | 其他项目只能使用 public 模型 | 将预期供其他项目使用的模型设为 access: public |
在 YAML 中将 access、group 或 contract 放在模型顶层属性中 | 会导致 Fusion 引擎解析失败;顶层位置不是有效配置 | 始终将其嵌套在 config: 下 — 例如:config: { access: public } |
| 为暂存模型添加契约 | 暂存模型属于内部模型 — 契约会增加阻力,却无法保护外部使用者 | 建议不要这样做;改为建议使用数据测试 |
| 为具有动态/透视列的模型添加契约 | 列列表会随数据变化,导致契约失效 | 建议不要这样做;说明列列表为何不是固定的 |
| 未确认存在外部使用者便添加契约 | 契约用于保护架构边界 — 没有使用者就没有需要保护的边界 | 添加契约前,先询问谁依赖此模型 |
将已在其组外被引用的模型设为 private | 现有引用会因 DbtReferenceError 而失效 | 先将访问级别放宽为 protected,或将调用方重构到同一组中 |
| 未确认 dbt Cloud Enterprise 就设置跨项目引用 | 较低套餐级别不支持跨项目 ref() | 在向 dependencies.yml 添加 projects: 或编写双参数 ref() 调用前,先确认套餐级别 |
上游尚无成功的生产作业便添加 dependencies.yml | dbt Cloud 通过上游的 manifest.json 解析跨项目引用 — 未运行作业就没有 manifest | 先在上游项目中至少运行一次成功的生产部署 |