前言

依旧先创个帖子激励自己……

贴一下用于vscode调试看代码的配置信息:

tasks.json

{
"version": "2.0.0",
"tasks": [
{
"label": "build DuckDB debug",
"type": "shell",
"command": "make",
"args": ["debug"],
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": ["$gcc"],
"detail": "Build DuckDB in debug mode"
}
]
}

launch.json

{
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug",
"program": "${workspaceFolder}/build/debug/duckdb",
"args": ["database_tpcc"],
"cwd": "${workspaceFolder}/build",
//"preLaunchTask": "build DuckDB debug",
//"externalConsole": true
}
]
}

然后就可以开始愉快的看代码了=.=

img

不对,有点神秘,还有goto?

果然是高端代码!

image-20251030125052376

摘一点官方讲解

DuckDB 执行一条 SQL 语句的整体流程

1. 解析阶段 (Parsing)

  • 核心步骤:将 SQL 字符串转换为令牌(如 ParsedExpression、TableRef、QueryNode、SQLStatement),不涉及目录或类型解析,仅语法检查。

  • 源代码文件/目录

    • src/parser/:解析器核心目录。

    • src/include/duckdb/parser/expression/comparison_expression.hpp:示例 ParsedExpression 类型。

    • src/include/duckdb/parser/:包含 ParsedExpression、TableRef、QueryNode、SQLStatement 的头文件。

    • 文件路径作用描述
      src/parser/parser.cpp核心递归下降解析器:处理 SQL 字符串 → Tokens → ParsedExpression/SQLStatement。生成初始 AST。
      src/parser/parsed_data/ (e.g., parsed_expression.cpp, sql_statement.cpp)定义 Parsed 结构:存储解析结果,如表达式树和查询节点,用于后续绑定。
      src/binder/binder.cpp绑定器:将 Parsed AST 转换为 Bound 形式,进行目录解析和类型绑定,为逻辑算子树铺路。
      src/planner/logical_planner.cpp逻辑规划器:从 Bound 结构生成逻辑算子树(LogicalOperator),如将 SELECT 转换为 Scan + Project 树。

2. 绑定阶段 (Binding)

  • 核心步骤:将解析节点转换为绑定形式,使用目录解析表/列,确定类型,提取聚合/窗口函数。

  • 源代码文件/目录:

    • src/binder/:绑定器目录(隐含)。

3. 逻辑规划阶段 (Logical Planning)

  • 核心步骤:从绑定语句生成逻辑操作符树(LogicalOperator)。

  • 源代码文件/目录

    • src/planner/:规划器目录。

    • src/include/duckdb/planner/logical_operator.hpp:LogicalOperator 定义。

    • 文件路径作用描述
      src/planner/logical_planner.cpp (续)生成初始逻辑算子树,作为优化输入。
      src/optimizer/optimizer.cpp优化器入口:运行规则序列(如 FilterPushdown、JoinReorder)重塑逻辑树。
      src/optimizer/rule/ (e.g., filter_pushdown.cpp, join_order.cpp)具体优化规则:改造算子树,e.g., 推送 Filter 到 Scan 节点。
      src/planner/physical_planner.cpp物理规划器:将优化逻辑树转换为物理计划,选择执行算法(如 HashJoinPhysicalOperator)。

4. 优化阶段 (Optimization)

  • 核心步骤:对逻辑树应用优化器序列,包括表达式重写(Expression Rewriter)、过滤推送(Filter Pushdown)、连接顺序优化(Join Order Optimizer,使用 DPccp 算法)、公共子表达式提取(Common Sub Expressions)和 IN 子句重写(In Clause Rewriter)。

  • 源代码文件/目录

    • src/optimizer/:优化器目录(隐含)。

5. 列绑定解析阶段 (Column Binding Resolution)

  • 核心步骤:将 BoundColumnRefExpression(引用表列)转换为 BoundReferenceExpression(引用 DataChunk 中的索引)。

  • 源代码文件/目录

    • src/planner/:规划器扩展。
    • src/include/duckdb/planner/expression/bound_columnref_expression.hpp:BoundColumnRefExpression。
    • src/include/duckdb/planner/expression/bound_reference_expression.hpp:BoundReferenceExpression。
    • src/include/duckdb/common/types/data_chunk.hpp:DataChunk 定义。

6. 物理规划阶段 (Physical Planning)

  • 核心步骤:将优化逻辑树转换为物理操作符树(PhysicalOperator)。

  • 源代码文件/目录

    • src/execution/:执行规划目录。
    • src/include/duckdb/execution/physical_operator.hpp:PhysicalOperator。

7. 执行阶段 (Execution)

  • 核心步骤:使用推送式向量化模型执行物理操作符,通过 DataChunk 推送数据产生结果。支持并行执行和溢出到磁盘。

  • 源代码文件/目录

    • src/execution/:执行引擎核心。

    • src/include/duckdb/common/types/data_chunk.hpp:DataChunk 处理。

    • 文件路径作用描述
      src/execution/physical_plan_generator.cpp计划生成器:最终组装物理树,准备执行。
      src/execution/physical_operator.cpp核心物理算子基类:定义 Execute 方法,每个算子(如 FilterPhysicalOperator)处理 DataChunk。
      src/execution/operator/ (e.g., scan_physical_operator.cpp, join_physical_operator.cpp, aggregate_physical_operator.cpp)具体算子实现:e.g., Scan 从表/文件读取 Chunk,Join 执行哈希匹配。
      src/execution/executor.cpp执行器入口:SinkManager 协调 Pipeline,推动执行并收集结果。
      src/common/types/data_chunk.cppDataChunk 定义:向量存储,用于批量推送/处理数据。

运行时涉及的文件和目录

DuckDB 在执行语句时会根据连接模式(:memory: 为内存模式,指定文件为磁盘模式)创建/访问文件。这些文件用于持久化、临时存储和配置。以下表格总结关键文件(相对路径基于数据库文件或工作目录):

文件/目录名称位置目的模式共享性
database_filename (e.g., mydb.duckdb)工作目录或指定路径主数据库文件,存储持久数据;在读/写语句中访问。磁盘模式-
database_filename.wal (e.g., mydb.wal)相对数据库文件写前日志(WAL),用于事务日志和崩溃恢复;在写操作中创建/访问。磁盘模式-
database_filename.tmp/ (e.g., mydb.tmp/)相对数据库文件临时目录,用于查询中间结果、排序/哈希溢出。磁盘模式-
.tmp/工作目录临时目录,用于内存模式下的瞬时操作(如中间结果)。内存模式-
~/.duckdbrc用户主目录 (~)CLI 初始化脚本;在 CLI 执行语句时读取。CLI仅 CLI
~/.duckdb_history用户主目录 (~)命令历史;在 CLI 会话中更新。CLI仅 CLI
~/.duckdb/extensions用户主目录 (~)扩展二进制文件;在加载扩展的语句中访问。所有跨客户端
~/.duckdb/stored_secrets用户主目录 (~)持久化秘密;在涉及认证的语句中访问。所有跨客户端/版本