Page 264 - 《软件学报》2026年第3期
P. 264
袁巩生 等: JIT 编译技术在可插拔存储引擎数据库中的应用 1227
略的代价. 针对可插拔引擎架构, 设计将 JIT 编译生成的谓词机器码下推至存储引擎层的近数据节点计算 (近数计
算) 方案. 在存储引擎执行过滤, 去除不符合条件的数据, 从而减少数据传输和中间层的句柄函数调用开销.
(4) 在开源数据库系统 MySQL 中实现上述提出的 JIT 代码生成技术, 称为 MySQLJ, 并对系统进行了详尽的
测试. 通过 Microbench 和 TPC-H 基准测试 [11] , 对比了不同数据量、多种数据类型、不同查询选择率下开启 JIT
编译选项前后系统的性能表现. 实验结果表明, MySQLJ 能够在不同的业务场景下自动选择最优的执行方案, 显著
提升数据库性能.
1 相关工作
在过去十多年中, JIT 编译技术已成为加速查询处理的关键技术. 本节将探讨 JIT 编译技术在数据库系统中的
最新研究进展.
查询发送到系统后, 由优化器生成物理查询执行计划. 编译器在该物理查询执行计划基础上使用代码生成方
法来生成本地代码. 总体来说存在两类方法来生成查询请求对应的代码. 一类是称为源到源的转译方法, 例如 HIQUE .
[12]
对于给定的查询计划, 转译生成一个实现查询执行的 C/C++程序, 其中包括所有谓词和类型转换. 然后使用现成的
编译器 (例如 gcc) 将代码转换为共享对象, 将其链接到数据库管理系统 (database management system, DBMS) 进
程, 并调用 exec 函数来执行查询.
另一类方法是 JIT 即时编译, 使用 JVM、LLVM 等编译基础设施生成查询的中间表示 (intermediate representation,
IR), 然后快速编译成本地机器码. 近年来, JIT 编译技术在数据库系统中的实现路径呈现多样化, 但受限于设计目
标与架构约束, 现有方案在适用场景与工程扩展性上存在显著差异. HyPer 的作者 [13] 认为使用转译的方法存在编
译速度慢、性能开销大等弊端 [2] . 因此 HyPer 转而使用即时编译技术. 作为这个技术的先驱, HyPer 自 2011 年引
入 JIT 编译技术, 主要关注扫描和处理大规模列式数据, 特别是在数据仓库和商业智能的场景中的应用. 最初
HyPer 利用 LLVM 编译器将查询操作编译成机器码, 摒弃传统的解释型执行流程. 为了克服 JIT 代码生成带来的
巨大开销, HyPer 研究人员提出使用自适应执行框架, 该框架通过预估算子剩余执行时间可以动态地在解释执行
和编译执行之间切换 [14] . HyPer 的演进版本——Umbra 数据库系统, 持续优化代码生成的开销. 研究人员 [15] 提出
了快速代码生成框架 Tidy Tuples. 它仅需单次遍历查询树即可生成代码, 并引入轻量级 IR 以支持快速代码生成和
编译. 类似地, Funke 等人 [16] 通过引入 Flounder IR 避免传统 IR 的复杂性与代码生成的耗时. Flounder IR 是专为数
据库查询处理设计的中间表示. 这种简化减少了编译过程中需要执行的分析和优化步骤, 从而缩短了编译的时间.
然而, HyPer 的优化高度依赖内存计算模型, 难以直接迁移至磁盘数据库或混合负载场景, 且其自研的 Tidy Tuples
框架需重构执行引擎, 导致与现有数据库生态兼容性不足. 相比之下, 本文提出的 JIT 编译方案基于通用的火山模
型设计, 通过非侵入式代码生成 (见第 3.3 节) 适配 MySQL 数据库, 无须重写存储或执行层, 避免了其他研究中自
底向上构建新引擎或重写编译器后端的复杂工作, 该方案面向通用的数据库执行器.
PostgreSQL [17] 是一个广泛使用的关系型数据库, 在 2018 年发布的版本 11 中同样通过使用 LLVM 编译器基
础设施引入了 JIT 编译 [18] , 目的是提升计算密集型操作的性能. 但其实现与存储引擎紧耦合, 无法适配存算分离或
可插拔架构的算子下推需求. 例如, PostgreSQL 的 JIT 编译代码仅在服务层执行过滤, 无法将机器码下推至存储引
擎层提前过滤数据, 导致冗余 I/O. 而本文提出的机器码下推方案 (见第 3.4 节) 通过字段裁剪与近数据计算, 在存
储层直接过滤非匹配记录, 减少了数据传输开销. 尽管 HyPer 和 PostgreSQL 都采用了 JIT 编译来提升查询性能,
但它们的 JIT 编译实现并未充分考虑现代数据库架构中的一些新兴需求, 尤其是在可插拔引擎和存算分离架构中
的适应性.
近年来, 不断有新的 JIT 编译框架与方法提出. Grulich 等人 [19] 提出了一个名为 Nautilus 的框架, 旨在结合查
询解释的易用性和查询编译的性能. 允许根据工作负载特性动态选择不同的编译后端, 以平衡编译时间和执行性
能. 并通过追踪技术, Nautilus 能够在运行时动态优化热代码路径, 减少编译时间并提高执行效率. Haffner 等人 [20]
提出了一种查询编译架构, 利用 WebAssembly 作为中间表示, 并使用 Google 的 V8 引擎作为后端. V8 提供了两级

