dbt 入门实战 用 DuckDB 把 SQL 脚本变成可测试的数据项目

很多数据项目一开始并不复杂:一份清洗订单的 SQL、一份汇总日报的 SQL,再加一个定时任务。真正难的通常不是写出第一条查询,而是半年后还能判断“改了这个字段会影响哪些表”“昨天的任务为什么没有报错却出了异常数据”。

把 SQL 文件放进 Git 能解决版本回溯,但不能自动说明依赖关系,更不会替你检查主键重复、状态值异常或空值混入。dbt 的核心作用,是把这些转换 SQL 组织成一个有依赖、有测试、有说明的数据项目。它在目标数据库中执行 SQL;它不是数据库,也不是采集工具。

这一区分很重要。原始数据如何进入仓库、任务何时调度、谁能访问生产数据,仍要由现有的采集、编排和权限体系负责。dbt 更擅长解决 ELT 中的 T:当数据已经落到仓库后,怎样可靠地把它变成可供报表和业务使用的数据集。

图片1.png

先建立一个最小目标

下面的练习只做一件事:从 raw.orders 中筛出已完成订单,生成“每个客户一行”的汇总表,并给关键字段加上数据测试。完成后,你会得到三个产物:一份模型 SQL、一份 YAML 元数据和一套可重复执行的命令。

环境可以选择 Windows、macOS 或 Linux,并准备 Python 与可用的命令行终端。dbt 的适配器需要与目标数据平台匹配;这里使用 DuckDB,因此安装的是 dbt-duckdb。正式开始前,应以所用 dbt 版本对应的官方安装说明为准,尤其是 Python 支持范围和配置字段。

mkdir dbt-lab cd dbt-lab python -m venv .venv ..venv\Scripts\Activate.ps1 python -m pip install --upgrade pip python -m pip install dbt-duckdb dbt init order_analytics cd order_analytics dbt debug

虚拟环境不是多余步骤:它能把 dbt 及适配器与其他 Python 项目隔离。dbt init 会创建项目骨架;dbt debug 用来检查项目配置、profiles 文件和数据库连接。若最后一步失败,先看终端明确指出的是 Python、profile 路径还是 DuckDB 文件权限,不要直接跳过。

把原始表声明成 Source

dbt 不要求所有表都由它创建。已有的订单表应该声明为 source,这相当于告诉项目:这张表是转换链路的输入,不要把它误当成某个模型的产物。

创建 models/orders.yml,用下面的最小配置登记源表。schema要与实际 DuckDB 中的 schema 一致;示例假定原始订单数据已经在 raw.orders 中。

version: 2 sources: - name: raw schema: raw tables: - name: orders description: "订单明细原始表,供客户订单汇总模型读取。"

source 的价值不仅是少写一个表名。后续模型会用 source() 引用它,dbt 因而可以在文档中画出上游关系。有人变更了原始字段、某张表不存在,排查路径也会更清楚。

用 ref 建模 而不是手写依赖顺序

接着创建 models/customer_order_summary.sql。这份 SQL 刻意保持短小,重点在于两个 dbt 函数:source() 指向外部输入,ref()用于引用其他 dbt 模型。当前模型只有 source;项目变大后,下游模型应通过 ref() 连接到它的上游模型,而不是把表名散落在多个 SQL 文件里。

{{ config(materialized='table') }} select customer_name, count(*) as completed_order_count, sum(quantity) as total_units_purchased, sum(quantity * unit_price) as total_revenue, avg(quantity * unit_price) as average_order_value, min(order_date) as first_order_date, max(order_date) as most_recent_order_date from {{ source('raw', 'orders') }} where order_status = 'completed' group by customer_name

materialized='table' 表示把查询结果落成表,适合这个小型汇总案例。实际项目还可以选择 view、incremental 或其他物化方式;选择取决于数据量、更新频率、成本和下游使用方式,不能因为“增量更快”就一开始套用。

运行模型时使用:

dbt run --select customer_order_summary

dbt 会先解析项目,再按依赖顺序编译并执行模型。这里也能看出它与“执行一堆 SQL 文件”的差别:顺序不是人工约定,而是从 source()和 ref() 建出的依赖图推导出来的。

把数据规则写进 YAML

模型能跑通只说明 SQL 可以执行,不代表结果适合被业务使用。订单汇总中,客户名为空会让“每客户一行”的含义变得模糊;原始订单状态出现未知值,则可能意味着上游字段约定发生了变化。把这类规则写成测试,比依靠人工发现更可靠。

在同一个 orders.yml 中补充模型和源表测试:

models: - name: customer_order_summary description: "按客户汇总的已完成订单数据集。" columns: - name: customer_name data_tests: - not_null - unique sources: - name: raw schema: raw tables: - name: orders columns: - name: order_status data_tests: - accepted_values: arguments: values: [completed, processing, returned, cancelled]

not_null和 unique 共同约束汇总表中的客户标识;accepted_values 则限制订单状态只能来自已约定的枚举。测试失败时,dbt 会显示失败规则和对应结果。它不会替你修正源数据,也不应把失败当成“可以忽略的红字”——先确定是上游数据异常、业务规则变更,还是测试写错了。

dbt test dbt build --select customer_order_summary

通常可以用 dbt test 单独检查已存在的数据对象;dbt build会按资源依赖运行选中范围内的构建与测试,适合在提交代码或部署流水线中做一次完整验证。不同 dbt 版本对 YAML 中测试键名的兼容情况可能不同:如果项目使用较早版本,应查看该版本文档,确认是否仍采用 tests而非 data_tests。

文档不是发布后另写一份

数据项目最容易过期的内容往往是文档。一个人离开项目后,表名还能找到,字段为什么存在、它依赖谁、状态值代表什么,却经常只能靠猜。

dbt 的做法是让描述、测试和模型定义靠近代码。为模型、source 和字段补上 description 后,执行以下命令即可生成项目文档:

dbt docs generate dbt docs serve

生成结果会包含元数据和关系图,便于查看模型的上游、下游及字段说明。文档页面是否能在本机打开取决于本地服务和端口环境;在团队环境中,通常需要把生成产物纳入发布流程,或接入统一的文档托管方式。

这里有一个容易忽略的原则:自动生成不等于自动写好。没有 description 的字段仍然只是一串技术名称。真正有用的文档要写出业务口径,例如“总收入是否含退款”“订单状态由哪个系统维护”“日期采用下单日还是支付日”。

从本地练习走到团队使用 还缺哪些环节

DuckDB 很适合把注意力放在模型和测试本身,但它不是所有生产场景的默认答案。连接 Snowflake、BigQuery、Redshift、Databricks 或其他数据平台时,需要改用对应适配器,并重新确认认证、权限、成本和并发策略。

把项目放到远程 Linux 环境长期运行时,重点也从“命令能执行”变成“失败能发现”。至少要考虑以下事项:

用 CI/CD 或编排工具执行 dbt build,不要依赖某台开发机手工运行。

为开发、测试、生产设置隔离的目标与最小权限,避免测试 SQL 误写到生产 schema。

记录运行日志和失败告警,并保留能定位编译 SQL 的构建产物。

按数据规模评估物化方式;全量表、视图和增量模型的成本与一致性取舍并不相同。

将远程环境部署在 Hostease 的服务器,优化生产效率。

一个可复用的 dbt 检查清单

在把新的数据模型交给下游前,可以按下面顺序检查:

source 是否指向真实、受管理的输入表。

模型之间是否使用 ref(),而不是复制粘贴表名。

每个关键字段是否有清楚的业务定义。

主键、空值、枚举值和关联关系是否有对应的测试。

本地是否跑过 dbt build,失败项是否已有归因。

生产环境是否具备权限隔离、日志、告警和回滚方案。

如果只是为了理解 dbt,上述 DuckDB 练习已经足够;如果准备把它接入真实数据仓库,下一步应先梳理业务口径和环境边界,再增加增量模型、宏、快照与 CI/CD。dbt 的价值不在于让 SQL 看起来更复杂,而在于让多人维护的数据转换更容易验证、追踪和交接。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容