Skip to content

DBT 数仓设计

本文由 Google Gemini 生成,仅供参考。

Table of Contents

Open Table of Contents

背景与痛点分析

当前项目的数据 ETL 流程高度依赖于在 DolphinScheduler 上调度的一系列独立 SQL 脚本,主要痛点包括:

  1. 逻辑重复与不一致:相同的业务逻辑在多个脚本中被反复复制粘贴,导致维护成本高,且存在逻辑不一致的风险。
  2. 隐晦的依赖关系:表间依赖完全由 DolphinScheduler 的 DAG 图“人肉”维护,追溯困难且容易出错。
  3. 数据一致性风险:由多个 INSERT 语句构成的任务,不具备原子性,若中间步骤失败,目标表将处于数据被部分加载的“脏”状态。
  4. 性能瓶颈担忧:对于数据量大的 ETL,将多个数据源的处理逻辑合并到一个查询中,存在内存溢出或超时的巨大风险。
  5. 调度与回溯的复杂性:当前依赖于向脚本传递 ${...} 变量来执行特定品牌或时间范围的数据回溯,方式缺乏规范,易出错。
  6. 缺乏数据质量保障:没有系统性的数据测试机制,数据问题只能在下游应用或报表中被动发现,响应滞后。

DBT 解决方案

核心原则:从“过程式”到“声明式”的思维转变

放弃:“先 TRUNCATE,再 INSERT A,再 INSERT B……”的过程式脚本思维。

拥抱:“我声明 final_table 的最终内容是 A、B、C 的并集”的声明式模型思维。

关键问题与 DBT 解决方案

  1. 如何应对大数据量下 UNION ALL 的性能风险?

    • 在 dbt/models/ 下创建 intermediate/ 目录。
    • 将原脚本中每一个独立的、复杂的 INSERT 源,都改造成一个独立的中间模型。
    • 最终的核心模型只负责对这些已经处理好的、干净的中间模型进行 UNION ALL。
  2. 如何保证数据一致性与任务执行顺序?

    • 执行顺序:当在模型 A 中写下 {{ ref('B') }} 时,就声明了 A 依赖于 B。
    • 数据一致性:
    • 原子性:dbt 对每个模型的构建都是事务性的。
    • 幂等性:dbt 模型是幂等的,失败后可简单重跑。
  3. 如何管理调度参数与数据回溯?

    • 在 dbt_project.yml 中为变量定义清晰的默认值。
    • 在 SQL 模型中通过 {{ var('hour', 3) }} 的方式引用。
    • 调度时通过命令行传入 JSON 来覆盖默认值实现精准回溯。
  4. 如何复用逻辑并保障质量?

    • 将 CASE WHEN 等通用转换逻辑封装成 macros(宏)。
    • 在任意模型中通过 {{ your_macro_name(...) }} 进行调用。
    • 在 .yml 文件中为模型的关键字段添加测试(如 unique,not_null,accepted_values)。

DBT 分层建模规范

核心理念:物理目录严格映射逻辑分层

我们采用“层级优先”的组织哲学,项目的物理目录结构必须清晰、直观地反映数据仓库的逻辑分层。开发者仅通过浏览目录,就应能理解项目的宏观架构。这种“约定优于配置”的原则是保障项目长期可维护性的基石。

一个理想的目录结构示例如下:

models/
├── staging/                            # 暂存层:源数据 1:1 镜像,只做最基础清洗
│   └── stg_{source}__{table}.sql
├── base/                               # 基础共享层:可被多层复用的通用逻辑
│   └── base_{domain}__{concept}.sql
├── dwd/                                # 明细数据层:业务过程的明细事实
│   ├── intermediate/                   # DWD 层的私有实现细节
│   │   └── int_dwd_{concept}.sql
│   └── dwd_{business_process}.sql
├── dws/                                # 公共汇总层:跨业务过程的公共汇总指标
│   └── dws_{domain}__{granularity}.sql
├── dim/                                # 维度层:高质量、一致的维度视角
│   └── dim_{dimension}.sql
└── marts/                              # 数据集市层(ADS):面向最终应用
    ├── intermediate/                   # Marts 层的私有实现细节
    │   └── int_marts_{concept}.sql
    └── {sub_domain}/                   # 按业务域划分子目录,如 marketing/
        └── ads_{report_name}.sql

公共分层

models/ 下的顶级目录定义了数据仓库的“公共 API”,它们是稳定、可信的,下游可以依赖。

  1. models/staging/ (暂存层)

    定位:ODS 源数据的“备菜区”,是源数据一个干净、可靠、1:1 的镜像。

    核心职责:对源表进行最基础的清洗和标准化(字段重命名、类型转换、基础清洗)。

    开发规则:一个 Staging 模型严格对应一个源表。禁止进行跨表 JOIN 和复杂业务逻辑。

  2. models/base/ (基础共享层)

    定位:跨层共享的“通用零件库”。

    核心职责:存放那些需要被多个、不同正式分层(如被 DWD 和 DWS 同时)共同消费的高度通用、基础的模型。

    开发规则:准入门槛高,只有真正被跨层复用的逻辑才能放入。

  3. models/dwd/ (明细数据层)

    定位:业务过程的“明细事实记录表”。

    核心职责:以业务过程(如下单、支付)中的一个行为主体为中心,关联相关维度,形成大宽表。保留最细粒度的数据。

    开发规则:主要进行跨表 JOIN 操作,一般不进行聚合(GROUP BY)。

  4. models/dws/ (公共汇总层)

    定位:面向分析主题的“公共汇总数据”。

    核心职责:基于 DWD 进行轻度聚合,形成跨业务过程的、可复用的汇总指标(如用户的每日活跃汇总)。

    开发规则:主要进行 GROUP BY 聚合操作。

  5. models/dim/ (维度层)

    定位:提供分析上下文的“维度视角”。

    核心职责:构建高质量、一致的维度表(如用户、商品、日期)。

    开发规则:通常从 Staging 或 DWD 层获取数据,进行清洗、去重、标准化。

  6. models/marts/ (数据集市层)

    定位:面向最终用户的“精品展厅”,即 ADS(应用数据服务层)。

    核心职责:从 DWS、DWD、DIM 层获取数据,构建面向特定业务应用(报表、分析、算法)的最终模型。

    开发规则:逻辑应尽可能简单,主要是字段选择和轻度关联。所有复杂计算都应已在 DWS 或 DWD 层完成。

  7. intermediate/ (私有中间实现)

    定位:任何公共分层内部的“私有草稿区”,用于封装复杂逻辑。

    核心职责:将一个复杂的模型(如一个 DWD 宽表)的构建过程,拆解为多个更小、更易于管理的步骤。

    开发规则:

    • 必须作为子目录存在,如 dwd/intermediate/。严禁创建顶级的 intermediate 目录。
    • 其中的模型应使用 int_ 前缀,并优先物化为 ephemeral。
    • 严禁被其父目录之外的任何模型 ref()。例如,DWS 层模型不应 ref() dwd/intermediate/ 里的任何模型。
  8. seeds/ (种子文件)

    定位:管理不常变化的、小规模的静态数据(如:日期维度表、平台信息映射表)。

    使用方式:通过 dbt seed 命令加载,在模型中通过 {{ ref('seed_file_name') }} 引用。

  9. tests/ (自定义数据测试)

    定位:实现复杂的、超越标准测试的业务规则校验。

    放置内容:任何返回 0 行即为通过的 SELECT 查询(如:校验 DWS 层总金额是否与 DWD 层明细总和相等)。

    目录组织:必须镜像 models/ 的顶级目录结构。对 models/dwd/dwd_trade_order.sql 的测试,应放在 tests/dwd/ 目录下。

  10. macros/ (宏)

    定位:封装可被项目全局复用的 SQL 代码片段,遵循 DRY 原则(如:map_order_status)。

核心建模原则与规范

数据流向:单向、逐层、不跨级

正确流向: source -> staging -> intermediate -> marts。

绝对禁止

类型转换的唯一位置:Staging 层

原则:所有对源数据的字段类型转换(CAST)必须且只能在 Staging 模型中进行。 目的:

命名规范

数据质量与测试

Schema Tests

用于对单个字段进行通用的、标准化的断言,直接在模型的 schema.yml 文件中定义:

Data Tests

用于执行任何复杂的、自定义的、甚至跨模型的业务逻辑校验:

测试执行

数据仓库运维与治理

文档与元数据管理

性能优化策略

数仓分层推荐物化方式核心原因与策略
Stagingview零存储开销,实时透传源数据,只做最基础的清洗。
Intermediateview 或 ephemeral过程数据,无需落盘。如果逻辑复杂,可物化为 table 以切断计算链,方便调试。
DWD (增量)incremental (自定义)【核心】 放弃默认 merge。首选分区替换策略,即计算出完整分区数据后通过 REPLACE PARTITION 原子化替换。如果 Doris 表是 UNIQUE KEY 模型,可直接 insert,利用其 UPSERT 特性。
DWS/ADS (全量)table面向最终查询,需要高性能。每日全量重刷,或通过自定义的 MERGE 逻辑更新(适用于状态型快照表)。
DWS/ADS (增量)incremental (分区)对于每日聚合的指标,直接按天分区 insert 即可,这是最高效、最简单的增量。

监控与告警机制

结合 DolphinScheduler 和 DBT 构建完整的监控体系:

版本控制与 CI/CD

DBT 在 Doris + DolphinScheduler 环境下的调度优势

精确的 DDL 控制

自动化的数据血缘

调度策略

大规模自动化调度(日常例行任务)

精细化手动操作(开发、调试、数据修复)