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 提供了两级
   259   260   261   262   263   264   265   266   267   268   269