当前位置:首页 > 技术 > 正文内容

利用Calcite实现自动化SQL执行计划优化

访客 技术 2026年6月8日 1

在现代数据平台架构中,许多系统通过可视化配置动态生成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)的双重优化策略。核心步骤包括:

  1. 使用SqlParser将原始SQL文本解析为抽象语法树(AST)。
  2. 通过SqlValidator进行元数据绑定与语义检查。
  3. 构建LogicalPlan并应用内置或自定义的优化规则集。
  4. 利用RelOptRule递归匹配并触发等价变换,如谓词下推、投影剪裁、连接重排序等。

后续文章将进一步剖析Hive内部基于Calcite的优化器工作原理,并展示如何构建轻量级独立优化服务。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。