这项由上海交通大学主导,联合清华大学、新加坡国立大学以及蚂蚁集团共同开展的研究,发表于2026年6月的ACM数据管理顶级期刊《Proceedings of the ACM on Management of Data》第4卷第3期(SIGMOD 2026),论文编号为Article 141,DOI为10.1145/3802018。
数据库,是现代软件世界的"粮仓"。银行记录你的每一笔转账,医院存储你的每一次就诊,电商平台追踪你的每一个订单,背后都有数据库在默默运转。而数据库里有一种东西,叫"原生函数"——你可以把它理解成数据库内置的"小工具箱",里面装满了各种预先写好的功能:算平方根、截断时间戳、拼接字符串、处理JSON格式数据……程序员只需呼唤一声,比如写下`date_trunc('hour', timestamp '2001-02-16 20:38:40')`,数据库就乖乖把时间精确到小时,返回`2001-02-16 20:00:00`。
这些小工具的数量,这些年一直在飞速增长。以PostgreSQL为例,从2018年的237个函数,到2026年的630个,翻了将近三倍;DuckDB从60个涨到666个;SQLite也从52个攀升到143个。驱动这场增长的,是不断涌现的新业务需求——比如企业要把Oracle数据库迁移到PostgreSQL,就得把那些Oracle独有的功能一一在新系统里重新实现,这项工作占到整个迁移预算的30%到60%,平均每一千行代码需要花费40到80个小时。
问题在于,给数据库手写这些"原生函数",极其困难。PostgreSQL的原生函数相关代码,光是两跳以内的依赖就超过11万9千行;DuckDB的GitHub代码仓库里,和函数相关的问题单多达3791条。每写一个新函数,开发者需要同时在多个文件里注册、实现、引用内部接口,稍有不慎就会酿成编译错误或者逻辑漏洞。这项工作长期依赖资深工程师的经验,难以自动化。
正是为了解决这个痛点,上述研究团队提出了一套名为**DBCooker**的自动化系统——借助大语言模型(也就是近年来广为人知的ChatGPT、Claude之类的AI),让机器自动完成数据库原生函数的代码合成。实验结果显示,DBCooker在SQLite、PostgreSQL和DuckDB三个主流数据库上,平均准确率比当前最强的对手(包括Anthropic的Claude Code、阿里巴巴的Qwen Code等)高出34.55%,并且成功为最新版SQLite(v3.50)添加了四大类此前完全不存在的新函数。
一、为什么让AI写数据库函数这么难?
要理解DBCooker解决了什么问题,先得摸清这件事到底难在哪里。
以PostgreSQL里的`date_trunc()`为例。这个函数的功能听起来简单:把一个时间戳"截断"到指定精度,比如截到小时、截到天。但在数据库内部,这一个SQL关键字,背后对应的是四个不同的"底层函数单元":处理带时区时间戳的`timestamptz_trunc`、处理时间间隔的`interval_trunc`、处理带时区信息的`timestamptz_trunc_zone`,以及一个内部辅助函数`timestamptz_trunc_internal`。开发者必须把这四个单元分别注册在系统目录文件`pg_proc.dat`里,然后在`src/backend/utils/adt/timestamp.c`这个源文件里逐一实现它们,还要正确引用数十个数据库内部的宏和工具函数,比如用`PG_GETARG_TEXT_PP()`获取输入参数,用`PG_RETURN_TIMESTAMPTZ()`格式化输出结果。
假如不借助这些现成的内部工具,从零实现`date_trunc()`需要6235行代码,涉及225个函数;而借助这些工具,只需要315行。节省了94.95%的代码量。这说明,正确识别和复用数据库内部的"参考函数单元",是整件事的核心难点之一。
研究团队通过大量观察,总结出了三个主要障碍。
第一个障碍,是"一对多的映射"。一个SQL层面的函数,在数据库内核里往往对应多个分工不同的底层单元,而且这种映射关系深埋在代码仓库的隐式约定里,没有明确文档,全靠经验。
第二个障碍,是"海量引用中的精准寻找"。数据库代码仓库极其庞大,以SQLite为例,每个文件平均有2619个可引用的函数和宏,但一个原生函数真正需要用到的,平均只有13.73个。在这片汪洋大海里找到那十几颗关键的"明珠",对AI来说并不容易。
第三个障碍,是"千人千面的复杂度"。有些函数,比如`sqrt()`,本质上就是套一个标准数学库,实现极简;有些函数,比如`json_agg()`,需要从头构建复杂的聚合逻辑,代码量可能是前者的数十倍。用一套固定流程统一对待它们,必然顾此失彼。
现有的AI代码生成工具,包括著名的Claude Code和Qwen Code,在面对这三个障碍时都暴露出明显短板。研究团队做过统计:Claude Code在合成数据库函数时,有63.70%的操作时间花在了"搜索仓库"和"读取文件"上,真正用于"生成代码"的时间只占4.95%。换句话说,它把大部分精力用来在浩如烟海的代码文件里找方向,而不是实实在在地写代码。与此同时,这些通用AI工具产生的错误里,有81.76%属于"声明错误"——要么把函数注册在了错误的地方,要么引用了根本不存在的内部接口。
这就是DBCooker要攻克的战场。
二、DBCooker的"烹饪哲学":先备料,再按方煮,最后严格验收
研究团队把这套系统命名为"DBCooker",这个名字颇有意思——数据库(DB)加烹饪者(Cooker)。确实,整套系统的逻辑,像极了一个专业厨师的工作方式:先弄清楚这道菜的配方和所需食材(函数特征化),再按照菜谱一步步下厨(函数合成操作),最后对成品进行严格的口味检验(代码验证),而且整个流程会根据菜肴的复杂程度灵活调整(自适应工具编排)。
整个系统由三大模块构成,彼此紧密协作。
第一大模块叫做"函数特征化",负责在开始写代码之前,把一个SQL函数需要的所有关键信息摸清楚——就像厨师在下锅前必须先备好料。这个模块从两条路径汇集信息:一条是解析数据库官方文档,提取函数的文字描述和使用示例;另一条是查询数据库系统目录(比如PostgreSQL的`pg_proc.dat`),获取精确的函数签名、参数类型、返回类型等代码层面的声明。把这两路信息合并成统一的JSON格式,就得到了一份完整的"函数档案"。
备好基础资料之后,这个模块还要做一件更精细的工作:在代码仓库里把这个SQL函数背后所有需要实现的底层单元一一识别出来。系统采用了一种"图遍历"的方法——把代码仓库里函数之间的调用关系想象成一张地铁线路图,从SQL关键字这个"起始站"出发,沿着调用关系一站一站往下走,把所有相关的底层函数单元都找出来,同时把那些全局通用、并非这个函数专属的单元排除掉。
找到所有相关单元之后,系统还会对同一类别的函数(比如所有处理时间的函数)做"成对比较":把两个同类函数的代码对齐,找出它们共同的固定部分和各自不同的变化部分,把固定部分提炼为可复用的"模板",把变化部分标记为需要填写的"空格"。这套"找相同、标差异"的逻辑,为后续的代码生成奠定了基础。
第二大模块叫做"函数合成操作",负责真正把代码写出来——也就是那位厨师实际下厨炒菜的过程。这个模块包含三个递进的环节。
第一个环节是"伪代码计划生成"。在真正写代码之前,系统先让AI生成一份详细的实现方案——不是真正的代码,而是一份像施工图纸一样的"骨架":标明每个底层单元放在哪个文件里,每个单元内部分几个代码块,每个代码块大概要用哪些内部接口。这就好比厨师在下锅之前,先在脑海里过一遍"第一步加盐、第二步翻炒、第三步收汁"的流程。为了确保这份计划的质量,系统会同时生成多份候选计划,然后用一个评分公式筛选出最好的那份。评分考虑两个维度:一是"可信度",即计划里列出的引用接口实际存在、文件路径实际正确的比例;二是"简洁性",即计划列出的函数单元数量不要过于冗余。两个维度加权平均,得分低于门槛的计划直接淘汰。
第二个环节是"填空式代码合成"。有了计划骨架之后,实际写代码的过程被设计成"填空题"而非"作文题"。系统从同类函数里提取那些带有空格标记的模板,把固定部分直接复用,让AI只专注于填写那些真正需要创新的、因函数而异的逻辑。这样一来,AI的注意力被精准引导到最关键的地方,而不是从头写起、容易在细节上出错。为了进一步提高质量,系统会同时生成多个候选实现,然后用"少数服从多数"的投票策略,选出出现频率最高的方案作为最终代码。
此外,这个环节还设计了一个"自动降级"机制。假如填空模板的质量不够好,或者多次生成的代码都以失败告终,系统会逐步降低对模板的依赖程度——就像一道复杂的菜谱执行失败几次之后,厨师会选择放弃照着菜谱做、转而凭自己的经验自由发挥。降级的速度由一个衰减参数控制,失败次数越多,越快切换到完全自由生成的模式。
第三个环节是"三阶段代码验证"。代码写完之后,要经历三关考核,才算真正合格。第一关是"语法检查",用ANTLR这类专业的语法解析工具,确认代码本身没有拼写错误、括号缺漏之类的低级问题。第二关是"合规检查",直接调用数据库的编译工具(比如PostgreSQL的`make install`),验证代码能否顺利编译并集成到数据库里。第三关是"语义验证",让AI自动生成一批测试用例——覆盖各种输入类型、边界情况和异常情况——然后实际运行这些测试,检查函数的输出结果是否符合预期。三关里任何一关不过,系统都会把错误信息反馈给AI,让它修改代码,直到全部通过为止。
第三大模块叫做"自适应工具编排",负责把前两个模块里的所有操作智能地串联起来——这就像那位厨师的"工作节奏管理",根据今天要做的菜有多复杂,灵活决定先做什么、后做什么。
系统把每一个可用的操作(生成计划、写代码、检查语法、编译验证……)都包装成一个标准化的"工具",然后由一个AI控制器实时决定下一步调用哪个工具。这个控制器不是盲目决策的,它会参考一个"历史经验库"——记录了过去合成类似函数时用过的操作序列,包括哪些函数只需要简单几步就搞定了,哪些函数需要反复迭代。每次遇到新函数,控制器会从历史库里找出同类别的参考案例,综合参考"最省事的做法"、"最费劲的做法"和"中间水平的做法",再结合当前的实时状态,动态决定接下来的行动。这种设计避免了"一刀切"——简单函数不会被迫走冗长的流程,复杂函数也不会因流程太短而留下隐患。
三、实验室里的成绩单:数据说话
为了检验DBCooker的实际效果,研究团队在SQLite、PostgreSQL和DuckDB三个主流数据库上进行了全面测试,分别测试了75、145和128个函数,涵盖数学函数、日期函数、字符串函数、JSON函数等多个类别,并设置了不同复杂度的函数样本。
与之对比的方法涵盖了目前最强的竞争者:直接用GPT-5、Claude Opus 4.1、Claude Sonnet 4.5、Qwen3 Coder Plus等大语言模型生成代码;在大语言模型基础上增加代码检索增强(CodeRAG)的版本;以及Claude Code、Qwen Code、TRAE(SWE-bench排行榜第一名)等专业代码智能体系统。
评估指标分两层:一是"合规准确率",即生成的代码能成功编译并集成到数据库的比例;二是"结果准确率",即生成的代码不仅能编译,还能在所有测试用例上输出正确结果的比例。
DBCooker在两项指标上都大幅领先。综合三个数据库,合规准确率达到78.90%,结果准确率达到65.19%,分别比其他方法的平均水平高出124.37%和149.68%。换句话说,DBCooker在正确率上大约是竞争对手平均水平的两倍以上。
按函数难度分层来看,DBCooker的优势在难度较高的函数上尤为明显。对于"简单"函数,各方法差距相对较小,DBCooker的合规准确率达到78.44%;但对于"困难"函数,其他方法的平均合规准确率只有约22%,而DBCooker仍然保持在68.97%,差距达到197.10%。这说明随着函数复杂度的增加,那些通用AI工具的能力急剧退化,而DBCooker的专项设计使它在复杂场景下依然保持稳定。
按函数类别来看,DBCooker在四大类PostgreSQL函数(数学、日期、字符串、JSON)上的合规准确率从89.19%到96.67%不等,整体稳定且均匀,比其他方法的平均水平高出151.11%。相比之下,竞争对手在不同类别上的表现参差不齐,尤其在数学函数这类看起来"简单"实则充满底层细节的函数上,大多数LLM方法合规准确率仅有6.67%到16.67%。
研究团队还做了一个有趣的补充实验:把正确的文件路径、函数声明和引用接口全部提前告诉那些竞争对手(相当于把所有"食材"都备好放在桌上),看看它们在彻底消除"文件搜索"障碍之后能达到什么水平。结果是,即便如此,这些竞争对手的准确率仍然比DBCooker低22.56%。这说明,数据库原生函数合成的难点,不仅仅在于"找到正确的文件",更在于生成符合数据库内核规范的代码本身——而这正是DBCooker通过三阶段验证和伪代码计划所着力解决的。
错误分布的分析同样印证了这一点。通用LLM方法产生的错误以"声明错误"为主,占到所有错误的约82%;Claude Code这类智能体工具虽然搜索能力更强,能主动验证声明位置,但生成的代码仍然频繁出现引用不存在接口的问题;DBCooker则通过函数特征化和三阶段验证,把各类错误压到了最低水平。
四、消融实验:每个零件都不能少
为了验证系统各模块的贡献,研究团队做了"拆零件"实验——每次去掉一个模块,看看准确率如何变化。
去掉"函数特征化"模块(即不再预先提取函数的声明信息和参考函数单元)时,三个数据库上的合规准确率分别从81.33%、78.62%、83.67%下降到68.0%、31.25%、44.90%。尤其PostgreSQL的降幅最大,说明对于结构复杂的数据库,预先理解函数组成至关重要。
去掉"三阶段验证"模块时,PostgreSQL的合规准确率从78.62%骤降至6.9%。这个极端的下降幅度,反映了PostgreSQL的内部依赖关系极其复杂,没有逐级验证反馈,AI生成的代码几乎无法自行收敛到正确状态。
单独去掉"伪代码计划生成"(保留三阶段验证)时,准确率从78.62%下降至37.04%;单独去掉"三阶段验证"(保留计划生成)时,如上所述降至6.9%;两者都去掉时则跌至9.66%。这表明计划和验证是相辅相成的——计划帮助AI构建全面的实现蓝图,验证帮助AI纠正执行过程中的错误,两者缺一不可。
去掉"自适应工具编排"(改为固定流程的多LLM协作)时,三个数据库上的结果准确率从69.33%、58.62%、67.35%分别下降到49.33%、21.19%、30.61%。这说明对于不同复杂度的函数,固定流程难以自适应地分配精力,而动态编排能有效提升资源利用效率。
五、让SQLite"学会"它从未会过的新技能
除了在已有函数上的测试,研究团队还做了一个更有野心的实验:把PostgreSQL和DuckDB里有、但SQLite里没有的函数,用DBCooker合成到SQLite里。
这项工作的难度更高,因为不同数据库的内部架构差异极大,代码不能直接移植,必须从头适配SQLite的内部规范。研究团队共尝试了17个新函数,涵盖聚合函数(如`covar_pop`、`bool_and`、`bool_or`)、日期函数(如`century`、`monthname`、`yearweek`、`last_day`)、数值函数(如`lcm`、`even`、`gamma`、`lgamma`、`nextafter`)和字符串函数(如`left`、`regexp_split_to_array`、`repeat`、`to_hex`、`translate`)。
DBCooker成功合成了全部17个新函数,而Claude Code合成了其中12个,TRAE合成了12个,Qwen Code只合成了7个。有几个函数,三个竞争对手都无法合成,只有DBCooker成功,包括`century`、`monthname`、`even`、`gamma`、`lgamma`、`nextafter`和`translate`。
以`covar_pop`(计算协方差的聚合函数)为例,DBCooker正确识别出它需要三个底层单元:`covarPopStep`(逐行累加中间结果)、`covarPopFinalize`(计算最终协方差值)和`covarPopInverse`(用于窗口函数的逆运算),并把这三个单元用SQLite专属的宏`WAGGREGATE`正确注册在`src/func.c`文件里,使得用户可以直接执行`SELECT covar_pop(...)`。Qwen Code则虽然正确注册了声明,但没有实现`covarPopInverse`,导致编译时报错"WAGGREGATE宏中xInverse未声明"。
以`regexp_split_to_array`(用正则表达式分割字符串为数组)为例,DBCooker正确使用了SQLite内部的`sqlite3_value_text`和`sqlite3_str_new`等引用接口;而其他三个方法则尝试引用外部文件`sqlite3re.c`里的`sqlite3re_compile`和`sqlite3re_match`,这两个接口在SQLite标准发行版里根本不存在,直接触发合规错误。
六、和其他相关工作的区别在哪里
这项研究和几个相邻领域的工作之间,边界是清晰的,值得简单梳理一下。
通用代码生成领域,涵盖Codex、GitHub Copilot这类"提示词驱动"的方法,Claude Code、SWE-Dev这类"智能体驱动"的方法,以及Code Llama、WizardCoder这类"训练驱动"的方法。它们都是面向通用代码仓库设计的,缺少对数据库内核架构的针对性理解,在数据库原生函数这个专项任务上效果有限——这一点已经被实验结果充分验证。
用户自定义函数(UDF)优化领域,代表性工作包括微软的Froid(把命令式UDF转换为关系代数表达式以提升执行效率)和Tuplex(把Python UDF编译为原生机器码)。这些工作聚焦的是"如何让已有的函数跑得更快",而不是"如何从零合成一个新函数并集成进数据库内核",和DBCooker的目标完全不同。
运行时代码生成领域,代表性工作包括HyPer(把查询计划编译为LLVM机器码)和Weld(为跨库数据分析流程生成优化的并行代码)。这些工作生成的代码是临时性的、面向单次查询执行的,而DBCooker合成的是持久性的、作为数据库内核一部分的原生函数。
数据库迁移领域,代表性工作包括CrackSQL(用LLM实现不同SQL方言之间的翻译)和PARROT(跨系统SQL翻译的评测基准)。这些工作处理的是SQL语句的表层语法转换,而DBCooker处理的是函数在数据库内核层面的重新实现,两者粒度和难度都不在同一层次。
七、展望:这套系统未来面对哪些挑战
研究团队在论文中坦诚地指出了三个值得持续关注的深层挑战。
第一个挑战,是"代码库的碎片化与长上下文推理的矛盾"。PostgreSQL的源代码超过一百万行,而且声明和实现往往分散在不同文件里(比如`pg_proc.dat`里是声明,`src/func.c`里是实现)。即便未来的AI模型能够处理超长上下文,把整个代码库一股脑塞进去,也会带来高昂的推理成本,而且AI很可能在信息量过大的时候迷失方向、遗漏关键细节。DBCooker通过"函数特征化"提前精准定位相关内容,是解决这一矛盾的有效路径。
第二个挑战,是"数据库的确定性正确性要求与AI的概率性生成本质之间的矛盾"。数据库函数必须在所有情况下都输出正确结果,没有"大体上正确"这一说。而AI生成内容的本质是概率性的,无法从根本上保证精确正确。DBCooker通过外部强制执行的伪代码计划和三阶段渐进验证,把概率性输出转化为可验证的正确实现,是应对这一矛盾的关键机制。
第三个挑战,是"数据库版本迭代与AI训练数据滞后之间的矛盾"。数据库函数的签名、内部宏的用法、系统目录的结构,会随版本更新而变化。AI模型训练时接触的是历史数据,难以跟上最新版本的变化,甚至可能把旧版本的写法带入新版本的代码里,造成隐蔽的错误。DBCooker通过动态检索当前版本的实现惯例,并用自适应工具编排加以强制执行,使系统能够直接适应版本变化而无需重新训练模型。
说到底,DBCooker做的事情,本质上是在为一项长期靠人工经验维系的高难度工作,设计了一套有章法、有记忆、能自我纠错的自动化流程。它并不是简单地把"让AI写代码"这件事重复一遍,而是针对数据库原生函数这个具体场景,把函数的结构分析、模板复用、分层验证和历史经验融合为一个有机整体。
对于数据库开发者和企业IT团队而言,这意味着那些长达数月的数据库迁移项目,其中最耗时的函数重实现部分,未来或许能够得到切实的自动化支持,而不再只是"AI能帮我搜索一些参考代码"这种程度的辅助。对于更广泛的软件工程领域而言,这项工作也提示了一个值得关注的方向:面对高度结构化、规范严格、内部依赖复杂的特定代码合成任务,专项化的设计比通用方法有着相当明显的优势空间。
有兴趣深入了解技术细节的读者,可以通过DOI 10.1145/3802018查阅完整论文,也可以访问GitHub上的开源代码库 weAIDB/DBCooker,复现实验或在自己的数据库项目中尝试应用。
Q&A
Q1:DBCooker和Claude Code这类AI编程工具相比,核心区别是什么?
A:Claude Code是通用代码智能体,遇到数据库原生函数合成任务时,会花大量时间在代码仓库里盲目搜索文件,真正用于写代码的时间只有不到5%,而且不了解数据库内部的注册规范,经常把函数声明放错地方或者引用根本不存在的内部接口。DBCooker则是专门针对数据库原生函数设计的,它预先分析清楚每个函数对应哪些底层单元、这些单元应该放在哪里、应该引用哪些内部接口,然后按照数据库内核的规范逐步生成和验证代码,把错误率压到了Claude Code的三分之一以下。
Q2:DBCooker的三阶段代码验证具体是怎么工作的?
A:三阶段验证是从浅到深的三关考核。第一关是语法检查,用专业的语法解析工具(ANTLR)扫描生成的代码,排除括号不配对、变量未声明之类的低级语法错误。第二关是合规检查,直接调用数据库自身的编译工具(比如PostgreSQL的make install命令),看代码能否真正编译并集成进数据库,这一关能发现函数注册位置不对、引用接口不存在等深层问题。第三关是语义验证,让AI自动生成覆盖各种输入类型和边界情况的SQL测试用例,实际运行后检查输出结果是否符合预期,这一关专门针对"代码能跑但结果不对"的情况。三关都通过才算合格,任何一关失败都会把错误反馈给AI让它修改。
Q3:DBCooker能用来给任意数据库添加新函数吗,有什么限制?
A:目前DBCooker已经在SQLite、PostgreSQL和DuckDB三个主流数据库上经过了系统验证,能够处理数学、日期、字符串、JSON等多个类别的函数,包括从其他数据库移植全新函数。主要的限制在于,DBCooker的函数特征化模块需要访问目标数据库的代码仓库和系统目录,对于闭源数据库或内部结构没有文档化的系统,适用性会受限。此外,对于极端复杂的函数(比如涉及几百个底层依赖的聚合函数),当前版本的成功率仍然低于理想水平,这也是研究团队正在持续改进的方向。
热门跟贴