![]()
![]()
在这篇文章中,我们将看到如何在Apache Calcite的帮助下为一个给定的查询创建物理(优化)树。
什么是Apache Calcite?
Apache Calcite是一个动态数据管理框架,包括SQL解析器、优化器、执行器和JDBC驱动。
Apache Calcite如何工作
假设我们有一个表,现在我们需要执行一个SQL查询。
val QUERY: String = """SELECT x from t
|""".stripMargin
.replaceAll("\\n", " ")
但问题是查询中没有告诉数据库引擎如何获取数据的细节,所以Calcite就出现了。
Calcite为我们提供了一些步骤,在这些步骤的帮助下,你可以创建一个优化的树。
因此,让我们讨论一下所有的步骤
第1步:解析
整个过程从解析开始。一个查询,为了被数据库引擎理解,必须首先使用SQL解析器进行解析,该解析器接收一串字符,并试图以解析树的形式推断其语法结构。
例如,解析SQL SELECT语句的规则可能看起来像这样。
<SELECT> expressionList
[<FROM> table]
[<WHERE> condition]
[<GROUP> <BY> groupingList]
[<HAVING> condition]
第2步:验证
为了验证,我们在AbstractSchema类 的帮助下创建我们自己的模式。我们扩展Apache Calcite的AbstractSchema类来定义我们自己的模式。并对查询进行验证。
让我们来看看模式的样子:
public class SimpleSchema extends AbstractSchema {
private final String schemaName;
private final Map<String, Table> tableMap;
private SimpleSchema(String schemaName, Map<String, Table> tableMap) {
this.schemaName = schemaName;
this.tableMap = tableMap;
}
@Override
public Map<String, Table> getTableMap() {
return tableMap;
}
}
一旦验证通过,我们就可以得到SqlNode(SqlNode是一个SQL解析树。它可以是一个操作符,字面意思,标识符,等等)。
第3步:翻译成关系代数
为了将查询表示为树状结构,我们需要关系 代数**(关系运算符**)。
关系代数处理的是数据集的 抽象 转换,例如:
- 选择: 基于一个谓词的过滤。
- 投影: 选择和修改某一行的某些列。
- 联合: 将几个行集合并为一个。
- 聚合: 在一个行集上计算一个标量函数。
AST(抽象语法树)不便于查询优化,因为其节点的语义太复杂。
在RelNode子类定义的关系运算符树上进行查询优化要方便得多,如Scan, Project, Filter, Join等。我们使用SqlToRelConverter,Apache Calcite的另一个巨大的类,将原始AST转换成关系树。
第4步:规划和优化
优化是一个将关系树转换为另一个关系树的过程。你可以用启发式或基于成本的计划器HepPlanner和VolcanoPlanner分别进行基于规则的优化。
你也可以做任何没有规则的手动重写树。Apache Calcite带有几个强大的重写工具,如RelDecorrelator和RelFieldTrimme。
我们将使用VolcanoPlanner来进行基于成本的优化。
现在我们使用我们的优化器来解析、验证和转换查询。
SqlNode sqlTree = optimizer.parse(sql);
SqlNode validatedSqlTree = optimizer.validate(sqlTree);
RelNode relTree = optimizer.convert(validatedSqlTree);
第5步:执行
产生的逻辑树看起来像这样:
LogicalAggregate(group=[{}], revenue=[SUM($0)]): rowcount = 1.0, cumulative cost = 63751.137500047684
LogicalProject($f0=[*($1, $2)]): rowcount = 1875.0, cumulative cost = 63750.0
LogicalFilter(condition=[AND(>=($3, ?0), <($3, ?1), >=($2, -(?2, 0.01)), <=($2, +(?3, 0.01)), <($0, ?4))]): rowcount = 1875.0, cumulative cost = 61875.0
LogicalTableScan(table=[[tpch, lineitem]]): rowcount = 60000.0, cumulative cost = 60000.0
总结
Apache Calcite是一个灵活的查询优化框架。在这篇博文中,我们展示了如何使用Apache Calcite解析器、验证器、转换器和基于规则的优化器来优化SQL查询。