本节摘要:持续集成回答「这段代码能不能合并」,持续部署回答「验证过的代码怎么到达生产」。本节搭一条数据项目够用的最简流水线:合并请求触发编译检查与受影响模型的选择性测试,绿灯才准合并;合并后自动发布到生产。重点讲清数据语境下 CI 与软件 CI 的两个不同——选择性执行与「数据验证慢」带来的节奏差异。
软件项目的习惯这里完全适用:任何代码变更不直接进主干,而是走合并请求,由流水线先体检。区别在体检单上——软件项目跑单元测试,数据项目跑的是「编译检查加模型测试」,而且有个关键差异:全量测试太慢,必须选择性执行。
一个几百个模型的项目,全量测试跑下来可能一小时起步;如果每个合并请求都全量跑,开发节奏直接被流水线拖死。dbt 的选择性执行解决这个问题:给定改动模型的清单(从合并请求的文件差异里解析出来),只跑「这些模型及其下游」——上游没变,不必重验;下游全验,因为改动的影响沿着依赖图向下传播。
# 合并请求流水线的核心三步(示意) # 第一步:编译检查——语法与依赖图问题在这里现形 dbt compile --select state:modified+ # 第二步:只跑受改动影响的模型(自身加全部下游) dbt build --select state:modified+ # 第三步:新鲜度检查——顺带确认源数据到货正常 dbt source freshness
三步里的状态选择参数是关键:它让 dbt 自己判断「哪些模型相对于上一次已构建的状态发生了变化」,配合加号表示「连同下游」。这条命令组合是数据 CI 的标准姿势,名称叫得直白——瘦 CI(slim CI):只验证需要验证的部分。
流水线的反馈直接挂在合并请求上:绿灯放行,红灯附上失败明细(哪个测试、返回了几行问题数据)。评审者看代码差异,流水线看行为差异,两道关都过才合并。
合并后的发布环节,数据项目与软件项目的差异就显出来了。软件的部署发布的是代码,部署完即生效;数据的部署发布的是代码加数据——新代码要等下一次构建才会产生新数据,而数据验证比代码验证慢得多。
因此数据项目的部署节奏常分两拍:
第一拍,代码发布。 合并后自动把新代码部署到生产环境(或部署到一个待激活的状态)。这一拍很快,分钟级。
第二拍,数据生效与验证。 下一次生产构建跑完,新代码才真正产出了数据。这一拍之后要有一次「生效验证」:核对关键模型的行数与核心指标和上一版代码的产出在预期范围内(逻辑变更的模型有预期差异,其余模型应该完全一致)。验证通过,发布才算闭环。
两拍之间的空档就是回滚窗口:如果第二拍的验证发现问题,回滚代码很轻(Git 回退再发布),但被新逻辑覆盖的数据需要修复——增量模型可以用「回拨水位重跑」补救(4.4 节档案三的手法),全量物化的模型等下一次构建自然覆盖。发布高风险逻辑变更时,选一个出问题后有足够修复时间的时点(比如工作日早上而不是周五晚上),这是数据发布排期的第一条常识。

不依赖托管平台,用开源工具搭的最小可用版本,按顺序配五件事:
这套清单在项目小于百个模型、团队小于十人时完全够用。规模再上去,值得买的东西主要是两样:托管的执行环境(免维护)与执行历史的可视化(免翻日志)——按 1.2 节的取舍框架,按人力成本算账即可。
💡 关键直觉:CI 的本质不是「自动化跑测试」,是把「合并权」从人的自觉移交给流水线的标准。没有 CI 时,能不能合并取决于评审者的耐心与眼力;有 CI 后,能不能合并取决于一个可复现的体检结果。人的判断留给「这段逻辑对不对」,机器的判断负责「这套代码跑不跑得动、过不过得了验收」。
这决定了 CI 的节奏设计。时长方面,瘦 CI 的体检(编译加选择性构建)通常在几分钟到二十分钟之间,取决于改动模型的下游规模——改一张底层贴源表,下游几十个模型全部要跑,体检自然长;改一张末端报表模型,几分钟收工。成本方面(按扫描计费的仓库),体检消耗的是真实算力,受影响链越长越贵。两个工程约束由此而来:改底层模型挑低峰期提请(下游链体检便宜些),以及给流水线设并发上限(防止多个合并请求同时跑体检把仓库算力挤爆)。
先别急着下结论,这种「本地绿、CI 红」的差异本身就是线索,常见成因按概率排:集成环境的数据形态与本地不同(5.1 节案例的变体——本地只有自己造的几行数据,CI 面对真实快照);依赖版本差异(本地手滑升级了某个包,CI 按锁文件装旧版);改动模型的上游在 CI 环境处于不同的构建状态。排查动作是让两边环境尽量对齐后重放——多数情况下,CI 环境更接近真相,因为它更接近生产。这背后的原则值得记住:本地验证证明「代码能跑」,CI 验证证明「代码在接近生产的环境里能过验收」,合并决策看后者。
回滚的粒度是「代码提交」而不是「环境状态」:把主干回退到上一个已知正常的提交(或直接还原那次合并),流水线重新部署——这就是 5.1 节「三套环境跑同一份代码」红利的兑现时刻:环境本身无状态(状态全在 Git 与仓库里),回滚等于把代码指针拨回去。需要预案的是数据侧:被新逻辑跑过的表,按 4.4 节的手法回拨水位重跑即可,全量物化的表等下一次构建自动覆盖。
不允许——这个口子一开,CI 就退化成「建议」。真正的解法在别处。第一,把大变更拆小:多数积压源于一次合并请求里塞了十个模型的改动,体检要跑完整下游链,又慢又容易红;拆成按模型逐个提交,每条的体检范围小,并行度反而上去了。第二,区分风险等级:只改模型描述与注释、不碰 SQL 的变更,可以配置成只跑编译检查不跑构建——体检单跟着风险走,而不是一刀切全跑。第三,积压本身是信号:说明评审带宽或体检时长出了问题,值得回头看一遍流水线的耗时分布。数据项目的 CI 纪律和代码项目一样:体检可以变快,通道不能绕开。
代码能安全到达生产了,最后一环是日常运转:谁按什么节奏跑、出了事谁先知道。下一节讲调度与监控。