本页简要介绍了DuckDB引擎的内部结构。
Parser
解析器将查询字符串转换为以下标记:
解析器不了解目录或数据库的任何其他方面。如果表不存在,它不会抛出错误,并且还不会解析任何类型的列。它只是将查询字符串转换为指定的一组标记。
ParsedExpression
ParsedExpression 表示 SQL 语句中的一个表达式。这可以是例如对列的引用、加法运算符或常量值。ParsedExpression 的类型指示它代表的内容,例如,比较被表示为 ComparisonExpression
。
解析后的表达式不具有类型,除了具有显式类型的节点,例如CAST
语句。表达式的类型在Binder中解析,而不是在Parser中。
TableRef
TableRef 表示任何表源。这可以是对基表的引用,但也可以是连接、生成表的函数或子查询。
QueryNode
QueryNode 表示 (1) 一个 SELECT
语句,或 (2) 一个集合操作(即 UNION
、INTERSECT
或 DIFFERENCE
)。
SQL 语句
SQLStatement 表示一个完整的 SQL 语句。SQL 语句的类型表示它是哪种类型的语句(例如,StatementType::SELECT
表示一个 SELECT
语句)。如果原始查询字符串包含多个查询,则单个 SQL 字符串可以转换为多个 SQL 语句。
Binder
绑定器将所有节点转换为它们的绑定等效项。在绑定器阶段:
- 表和列使用目录进行解析
- 类型已解析
- 聚合/窗口函数被提取
以下转换会发生:
- SQL语句 →
BoundStatement
- 查询节点 →
BoundQueryNode
- TableRef →
BoundTableRef
- 解析表达式 →
Expression
逻辑规划器
逻辑规划器从绑定的语句中创建LogicalOperator
节点。在这个阶段,实际的逻辑查询树被创建。
Optimizer
在逻辑规划器创建了逻辑查询树之后,优化器会在该查询树上运行以创建优化的查询计划。以下是运行的查询优化器:
- 表达式重写器: 简化表达式,执行常量折叠
- 过滤下推:将过滤器下推到查询计划中,并在等价集合上复制过滤器。同时修剪保证为空的子树(因为过滤器静态评估为假)。
- 连接顺序优化器: 使用动态编程重新排序连接。具体来说,使用了论文动态编程反击中的
DPccp
算法。 - 公共子表达式: 从投影和过滤节点中提取公共子表达式,以防止不必要的重复执行。
- In Clause Rewriter: 将大型静态IN子句重写为MARK连接或INNER连接。
列绑定解析器
列绑定解析器将引用特定表列的逻辑BoundColumnRefExpresion
节点转换为引用执行引擎中传递的DataChunks中特定索引的BoundReferenceExpression
节点。
物理计划生成器
物理计划生成器将生成的逻辑操作符树转换为PhysicalOperator
树。
执行
在执行阶段,物理操作符被执行以生成查询结果。
DuckDB使用基于推送的向量化模型,其中DataChunks
被推送到操作符树中。
更多信息,请参见演讲DuckDB中的基于推送的执行。