利用Calcite实现自动化SQL执行计划优化
在现代数据平台架构中,许多系统通过可视化配置动态生成SQL语句以快速构建报表和图表。虽然这种方式极大提升了开发效率,但其生成的SQL往往存在明显的性能缺陷。本文探讨如何借助Apache Calcite框架,对这类自动生成的低效SQL进行自动重写与优化。
典型低效SQL案例分析
以下是一个由配置系统生成的典型低质量查询:
SELECT
t0.tree_id,
SUM(t0.gap) AS num
FROM (
SELECT
w.tree_id,
w.gap,
r.executed_sql
FROM data_middleground.view_mkt_node_kpi_warning w
JOIN data_middleground.view_mkt_node_result r
ON w.tree_id = r.tree_id
WHERE w.warning_status = 0
AND r.is_del = 0
) t0
WHERE t0.gap > 1
GROUP BY t0.tree_id
ORDER BY tree_id DESC
该语句的主要问题包括:
- 谓词未下推:过滤条件分布在子查询内外,未能尽早应用以减少中间结果集大小。
- 缺乏过滤合并:多个独立的WHERE条件未被整合到数据源扫描阶段。
- 聚合无法下推:本可在Join前完成的部分聚合操作被延迟至最后阶段。
原始执行计划结构
未经优化的逻辑执行计划如下所示:
LogicalSort(sort0=[$0], dir0=[DESC])
LogicalAggregate(group=[{0}], num=[SUM($1)])
LogicalProject(tree_id=[$0], gap=[$1])
LogicalFilter(condition=[>($1, 1)])
LogicalProject(tree_id=[$0], gap=[$1], executed_sql=[$4])
LogicalFilter(condition=[AND(=($2, 0), =($5, 0))])
LogicalJoin(condition=[=($0, $3)], joinType=[inner])
EnumerableTableScan(table=[[data_middleground, view_mkt_node_kpi_warning]])
EnumerableTableScan(table=[[data_middleground, view_mkt_node_result]])
优化后的高效版本
经优化器处理后,SQL被重写为:
SELECT
`t0`.`tree_id`,
SUM(`t0`.`gap`) AS `num`
FROM (
SELECT *
FROM `data_middleground`.`view_mkt_node_result`
WHERE `is_del` = 0
) AS `t`
INNER JOIN (
SELECT *
FROM `data_middleground`.`view_mkt_node_kpi_warning`
WHERE `warning_status` = 0
AND `gap` > 1
) AS `t0`
ON `t`.`tree_id` = `t0`.`tree_id`
GROUP BY `t0`.`tree_id`
ORDER BY `t0`.`tree_id` IS NULL DESC, `t0`.`tree_id` DESC
优化后执行计划
新的执行流程显著改善了执行路径:
LogicalSort(sort0=[$0], dir0=[DESC])
LogicalAggregate(group=[{0}], num=[SUM($1)])
LogicalProject(tree_id=[$0], gap=[$1])
LogicalProject(tree_id=[$0], gap=[$1], executed_sql=[$4])
LogicalJoin(condition=[=($0, $3)], joinType=[inner])
LogicalFilter(condition=[AND(=($2, 0), >($1, 1))])
EnumerableTableScan(table=[[data_middleground, view_mkt_node_kpi_warning]])
LogicalFilter(condition=[=($2, 0)])
EnumerableTableScan(table=[[data_middleground, view_mkt_node_result]])
关键改进点:
- 所有过滤条件均已下推至表扫描节点,大幅减少参与连接的数据量。
- Join两侧的子查询各自完成本地过滤,提升整体吞吐效率。
- 排序字段显式处理NULL值,确保语义一致性。
技术实现路径
上述优化能力可通过集成Apache Calcite实现。Calcite提供了一套完整的SQL解析、校验、转换和优化框架,支持基于规则(RBO)和基于成本(CBO)的双重优化策略。核心步骤包括:
- 使用SqlParser将原始SQL文本解析为抽象语法树(AST)。
- 通过SqlValidator进行元数据绑定与语义检查。
- 构建LogicalPlan并应用内置或自定义的优化规则集。
- 利用RelOptRule递归匹配并触发等价变换,如谓词下推、投影剪裁、连接重排序等。
后续文章将进一步剖析Hive内部基于Calcite的优化器工作原理,并展示如何构建轻量级独立优化服务。