一个 4B 参数的开源小模型,经过监督微调和智能体强化学习训练,能替 Postgres 生成比默认规划器更快的执行计划。在 113 条真实分析查询上,三条轨迹取最优的口径下几何平均加速 1.81 倍,单轨迹自选口径是 1.40 倍,训练总花费约 1200 美元。这套方法能成立,靠的是奖励可验证,一个计划跑得快不快,直接执行一次就能测出来。
问题出在规划阶段的估算
join 顺序的搜索空间是 NP-hard,Postgres 在规划阶段只能靠统计信息估算基数,做不了真实计数。均匀分布假设在真实数据上经常失效,估算偏差会让选出的计划慢几十倍。验证一个计划很容易,生成一个好计划很难,这种不对称正好适合强化学习,奖励信号客观而且廉价。
整体方法长什么样
模型不直接改 SQL,也不替换规划器,而是输出一组提示,让 Postgres 规划器改走别的路径。实现依赖 pg_hint_plan 扩展,提示写在 SQL 注释里,比如 HashJoin、SeqScan、Leading 这类指令。
智能体有六个工具,inspect_relation 看表结构,get_column_stats 读列统计,get_plan 取当前计划,evaluate_candidate 实测候选计划,keep_default 放弃改动,finish 结束任务。模型每轮输出一个 PlanAction 对象,编译成提示注入查询,然后实测拿反馈。
训练流程的具体步骤
- 先做监督微调。学生是 4.66B 基座的蒸馏版本,训练数据来自更强模型的推理摘要,只有摘要,不含原始推理过程。
- 套 LoRA 适配器,体积 42.5MB,可训练参数 21.2M。
- 进入智能体强化学习。策略在环境里跑多条轨迹,逐条打分,算相对优势,再更新参数。实现里用自研的 anchored GRPO 替换了常规版本,常规实现会把等于默认计划的方案当成好行为强化。
结果与应有的口径
训练到 600 次更新时,113 条查询全部可评分,没有一条出现回归,几何平均加速 1.35 倍。到 1200 次更新,几何平均 1.41 倍,工作负载整体加速 1.29 倍。
1.81 倍属于另一个口径,把三次轨迹的最优结果算进来。单次推理的实际水平更接近 1.4 倍。选型评估时要按自己的调用方式选择口径,每次请求只跑一条轨迹的场景,不该拿 1.81 倍做预期。
模型学到的策略可以复述。多数情况下它先看表结构和默认计划,再尝试重排 join 顺序。一个极端案例里,它推翻了一种有损的顺序扫描,强制改用位图扫描,单条查询快了 90 倍。动作统计里,扫描类提示 1141 次,join 树重排 917 次,并行提示 572 次。
容易踩的坑
- 测量噪声会骗过奖励。默认计划的重复测量本身有 5% 左右误差,实验里约 20% 概率把无改动判定为改进。测速环境没调稳之前,强化学习训出来的可能是噪声。
- 监督微调要控制轮次。3 轮训练的模型反而比 2 轮差,验证损失却是平的。从这组实验得到的提醒是,验证损失平说明不了模型没在退化。
- 小模型默认不会用工具。初始版本输出无效动作、漏掉 join 关系、工具调用时机错误,全靠监督微调先把格式教会。
成本与适用条件
训练跑在一块 H100 上约 95 小时,推理环境是两卡 RTX 3090,加 API 调用费合计约 1200 美元。适合参考的场景是分析型负载反复执行、单条查询够慢、调优人力有限。交互式短查询和写多读少的库,收益摊不平训练成本。
常见问题
- 能直接用现成模型吗。方法依赖这六个工具和评分环境,换模型要重新训练。
- 需要改 Postgres 吗。装 pg_hint_plan 扩展就行,主线版本不用动。
- 适合多大团队。查询模式稳定、回归测试齐全的团队收益最直接。