写点什么

Apache Cloudberry 向量化实践(三):Gandiva 优化实战

  • 2025-07-11
    北京
  • 本文字数:1765 字

    阅读完需:约 6 分钟

在向量化执行系统中,表达式构建是不可或缺的基础环节。无论是 SQL 中的投影、筛选,还是分区、聚合、排序,最终都需转化为底层执行引擎能识别和执行的表达式树。而在 Apache Cloudberry 向量化执行框架中,这一过程由 Gandiva 表达式引擎负责完成。

随着数据规模与查询复杂度的提升,我们逐渐意识到,表达式构建本身正成为影响执行性能的关键路径之一。特别是在高并发、多表达式拼接的场景下,构建过程的性能瓶颈愈加突出。本文将结合实际优化案例,分享我们如何识别问题、设计优化方案,并用火焰图验证成效。

为何选 Gandiva?

Gandiva 是 Apache Arrow 项目中的子模块,它基于 LLVM 构建 JIT 编译能力,专为高性能、批量化的列式计算而设计。我们选择 Gandiva 作为表达式引擎的主要原因有三点:

  1. 向量化执行友好:Gandiva 表达式以 Arrow RecordBatch 为输入/输出单位,与 Cloudberry 的内存格式完全兼容,避免额外序列化/反序列化开销。

  2. JIT 编译能力强:Gandiva 支持将表达式编译为本地机器码,执行效率显著优于解释执行。

  3. 表达式树抽象清晰:其表达式结构基于语法树(AST),便于分析、合并、转换、优化。

但“强大”背后也隐藏着一个问题:表达式构建过程并非“零成本”,尤其在表达式数量和深度快速增长时,构建开销成为了不容忽视的负担。

原始构建路径问题

在未优化前,我们采用“逐表达式构建”的方式——每处理一条 SQL 表达式,就从头创建一棵新的表达式树。这种策略在简单查询下运行良好,但在复杂嵌套查询、窗口函数、联表计算等场景下暴露出以下问题:

  1. 公共子表达式重复构建:同一表达式片段(如 lower(colA))在不同上下文中多次出现时,每次都重新生成节点,造成冗余。

  2. 表达式树结构深且复杂:表达式链条变长时,嵌套层级加深,构建耗时近似呈线性增长。

  3. Hash 逻辑不稳定:相同表达式结构,由于构建路径差异导致节点 hash 不一致,影响缓存和优化判断。

我们对典型查询的表达式构建过程进行了耗时统计,结果显示:

  • 在包含 20+ 表达式的复杂查询中,表达式构建耗时占整体查询时间的 10%~15%;

  • 其中约 40% 的表达式为可复用的子表达式,但未被有效识别与复用;

  • 构建阶段的所有开销几乎全部集中在 on-CPU 路径上,火焰图显示 CreateExpressionNodeToArrowNode 等函数在 CPU 调用栈中占比极高,成为构建瓶颈的主要耗时点。

这些现象表明:表达式构建过程不仅费时,而且浪费资源。

优化策略:公共子表达式识别+哈希原子化

我们采用两项优化手段来重构表达式构建路径:

1. 公共子表达式识别(CSE)

引入表达式 DAG 结构,在构建过程中为每个子表达式生成唯一 key(基于语义签名),并放入全局表达式缓存池。后续若再次请求相同表达式,直接复用已有子树。

  • 优点:减少冗余节点构建,降低构建深度;

  • 技术点:等价表达式归一化(如 a + b vs b + a)、表达式 hash 去重。

2. 哈希表达式原子化

将每一个表达式节点封装为具有确定性 hash 的原子单元,避免因构建路径差异导致 hash 冲突。统一采用 结构 hash + 类型信息 + 参数签名 的组合哈希策略,确保缓存命中率提升。

优化后,我们实现了表达式构建路径的“结构性去重”:从构建“树”转为拼装“块”,如搭积木般复用构建单元,降低系统负担。

优化效果对比

通过对比优化前后在复杂 SQL 下的表达式构建过程,我们观察到以下显著变化:

构建树节点数量明显下降,构建时间降低超过 50%,特别是在复合查询中表现尤为明显。

火焰图验证:on-CPU 时间显著下降

我们进一步通过 perf 工具配合火焰图对比优化前后的 CPU 使用情况,焦点集中在表达式构建阶段。

  • 优化前的火焰图中,Gandiva::TreeExprBuilder::MakeExpression() 及其内部调用占据主火焰图的 30% 高度,显著吞噬 on‑CPU 资源。

  • 优化后,该函数堆栈深度显著缩减,仅占主图不到 10%,并可见更多时间释放给后续执行逻辑,如 EvalFilterProject 等。

这说明:表达式构建从 CPU 消耗的“主角”,退回到了其应有的“配角”角色。

表达式构建常被认为是“编译期行为”,但在现代向量化系统中,它的性能表现直接影响执行链路的起跑速度。

通过本次优化,我们验证了如下几点:

  • 表达式构建本身具有显著的优化空间;

  • 结构性去重 比单纯加快构建速度更有效;

  • 可观测性工具(如火焰图)是评估优化效果的关键利器。

这也为后续优化其他执行环节(如重分布、调度、缓存)提供了经验模板:先观测,再定位,再结构重构。

用户头像

还未添加个人签名 2021-03-10 加入

酷克数据是中国领先的云原生数据仓库软件公司,致力以领先技术降低大数据分析的门槛和成本,我们的产品广泛应用于金融、运营商、能源等领域,帮助企业构筑稳定高效、自主可控的数据底座。

评论

发布
暂无评论
Apache Cloudberry 向量化实践(三):Gandiva 优化实战_酷克数据HashData_InfoQ写作社区