Doris 实战与架构

分析型数据库 / 源码阅读 / LESSON 25

源码贡献与调试——从读懂 Doris 到能改 Doris

从 Query ID、EXPLAIN、Profile 和源码地图出发,学习复现、调试、测试和贡献 Doris。

阅读时间
60 分钟
学习路径
Doris 实战与架构
内容来源
Doris 深度笔记

预计阅读时间: 60 分钟 前置阅读: 全部 Doris 课程, 尤其是 doc-01, doc-03, doc-04, doc-06 下一次阅读: doc-26(可观测数据最佳实践)


1. 专家的最后一公里

从使用者到专家, 有一道分界线:

能解释现象
  → 能定位源码
    → 能构造复现
      → 能修改并验证
        → 能把风险讲清楚

你不一定每天给 Doris 提 PR, 但如果要成为这一领域的专家, 至少要能:

  • 从 SQL 找到 FE/BE 调用链。
  • 根据 Profile 定位到 Operator 或 Storage 模块。
  • 本地复现一个查询、导入或 Compaction 问题。
  • 看懂测试失败。
  • 写出最小修复或最小验证 patch。

参考:


2. 源码地图回顾

fe/
  fe-core/
    mysql/              MySQL 协议入口
    qe/                 ConnectContext、Coordinator、StmtExecutor
    nereids/            新优化器
    catalog/            元数据模型
    transaction/        事务管理
    load/               导入任务
    persist/            Journal / EditLog

be/
  src/
    exec/               算子和旧执行框架
    exec/pipeline/      Pipeline 执行引擎
    vec/                向量化表达式和列类型
    storage/            Tablet、Rowset、Segment、Compaction
    runtime/            RuntimeState、MemTracker、RuntimeFilter
    service/            Thrift/BRPC/HTTP 服务
    common/             Metrics、配置、工具

定位入口:

问题入口
SQL 解析和执行ConnectProcessor, StmtExecutor
优化器规则fe-core/.../nereids
Fragment 调度Coordinator
Pipeline 执行PipelineTask, Operator
Scan 慢OlapScanOperator, SegmentIterator
写入问题StreamLoad, DeltaWriter, MemTable
CompactionCompaction, Tablet
元数据异常Catalog, EditLog, BDBJE

3. 从 Query ID 到源码

一次慢查询的源码定位:

query_id
  → audit log 找 SQL
    → EXPLAIN 找计划
      → Profile 找最慢 Operator
        → Operator 名称映射到 BE 类
          → 找指标和日志
            → 构造最小复现

例如 Profile 显示 OlapScanOperator 慢:

  1. 检查 Partition/Tablet 裁剪。
  2. 检查 Segment 数和 Rowset 版本。
  3. 检查索引过滤指标。
  4. 进入 be/src/exec/operator/olap_scan_operator.*
  5. 继续追 SegmentIterator, BlockReader, index reader。

如果是 HashJoinProbeOperator 慢:

  1. 看 Build/Probe 行数。
  2. 看 RuntimeFilter 是否生效。
  3. 看 Exchange 是否倾斜。
  4. 进入 Join Operator 和 Hash Table 实现。

4. 最小复现

优秀 issue 或 PR 的起点是最小复现。

CREATE TABLE repro_t
(
    dt DATE,
    k BIGINT,
    v STRING
)
DUPLICATE KEY(dt, k)
PARTITION BY RANGE(dt)
(
    PARTITION p20260727 VALUES [('2026-07-27'), ('2026-07-28'))
)
DISTRIBUTED BY HASH(k) BUCKETS 3;

INSERT INTO repro_t VALUES
('2026-07-27', 1, 'a'),
('2026-07-27', 2, 'b');

EXPLAIN SELECT * FROM repro_t WHERE dt = '2026-07-27' AND k = 1;

复现要求:

  • 数据量尽量小。
  • SQL 尽量短。
  • 表结构保留关键属性。
  • 参数明确。
  • 预期结果和实际结果都写清楚。
  • 如果是性能问题, 给出前后 Profile。

5. FE 调试思路

FE 是 Java, 常见关注:

  • 解析、分析、权限。
  • Nereids 计划生成。
  • 统计信息和代价。
  • Catalog 元数据。
  • Journal 和 HA。
  • Load Job 调度。

调试策略:

1. 用日志定位请求入口
2. 在 StmtExecutor / Nereids 入口加断点
3. 打印 Logical Plan 和 Physical Plan
4. 检查 Session Variable
5. 检查统计信息
6. 用单元测试固定复现

常见输出:

EXPLAIN VERBOSE SELECT ...;

不要只看最终计划, 要看规则为什么没有触发:

  • Pattern 不匹配。
  • 统计缺失。
  • Session 开关关闭。
  • 语义不等价。
  • 成本比较没有获胜。

6. BE 调试思路

BE 是 C++, 常见关注:

  • Pipeline 调度。
  • 向量化表达式。
  • Scan 和索引。
  • Join/Aggregation/Sort。
  • 内存和 Spill。
  • Storage 和 Compaction。

调试策略:

1. Profile 确认 Operator
2. 打开相关日志
3. 找到 Operator::get_block / sink / close
4. 检查 RuntimeState 和 MemTracker
5. 检查 Block 行数和列类型
6. 用小数据复现
7. 写 BE 单元测试或回归 SQL

性能问题要避免只凭感觉改代码。至少用一种证据:

  • Profile 前后对比。
  • 火焰图。
  • 指标变化。
  • 微基准。
  • 回归测试。

7. 测试分层

层级用途
FE 单元测试解析、分析、优化器规则
BE 单元测试数据结构、表达式、存储组件
Regression SQL端到端 SQL 行为
P0/P1 用例核心稳定性
性能基准防止优化退化

一个专家级修复必须回答:

  • 覆盖了哪个失败场景。
  • 是否影响兼容性。
  • 是否影响性能。
  • 是否影响存量数据。
  • 是否需要配置开关。
  • 如何回滚。

8. 选择第一个贡献点

不要一上来改 Nereids 大规则或存储格式。更好的起点:

  1. 文档修正或示例补充。
  2. 错误信息优化。
  3. 小型 SQL 回归用例。
  4. Profile 指标展示补充。
  5. 明确边界的小 bug。
  6. 某个函数或类型的兼容问题。

避开:

  • 需要重构多个子系统的问题。
  • 没有复现的性能优化。
  • 只在本地环境出现的模糊 bug。
  • 缺乏测试的行为改动。

9. 专家成长路线

阶段 1: 会用
  建表、导入、查询、看 Profile

阶段 2: 会调
  解释慢 SQL、调表结构、调 MV、管资源

阶段 3: 会运维
  处理副本、扩容、备份、升级、事故

阶段 4: 会读源码
  能把现象定位到 FE/BE 模块

阶段 5: 会贡献
  能复现、修复、测试、说明风险

最后的学习方式:

  • 找 5 条真实慢 SQL, 写完整调优报告。
  • 做一次从 Kafka 到 Doris 的 CDC POC。
  • 设计一套日志/Trace/指标表。
  • 演练一次 BE 下线和副本修复。
  • 给 Doris 提一个文档或测试 PR。

一句话总结:

Doris 专家的标志不是记住所有参数, 而是能把业务问题、运行证据、源码路径和可验证修复连成闭环。