开发者生态
morning
训练 4B 模型生成比 Postgres 快 81% 的查询计划
摘要
How good are query optimizers, really? Leis et al. asked this exact question in 2015. Then, they asked it again 10 years later . Despite an enormous body of research spanning a decade since their orig...
query
that
the
Postgres
hard
plans
good
and
across
are
2026-09-17
1 阅读
约8分钟阅读
polyphilz
字号:
查询优化器到底有多好?莱斯等人。 2015年,他们问了这个问题。10年后,他们又问了一遍。尽管自最初的探索以来已经进行了十年的大量研究,但他们发现查询优化器仍然有很多不足之处。当我第一次得知这一点时,我很惊讶。 Postgres 数据库应该了解其表中内容的所有信息,不是吗?这有多难?事实证明:非常困难。事实上,查询优化器需要执行的一项特定任务(连接排序)被认为是 NP 困难的。所以查询优化器很难。验证优化器选择的查询计划是否良好并不困难。简而言之,一个好的查询优化器会产生运行速度快的计划,而一个不好的查询优化器会产生运行速度慢的计划。语言模型特别擅长学习如何完成具有易于验证输出的任务。因为只有一个轴需要优化——查询的执行时间——这个问题完美地简化为强化指导模型生成更快查询计划的行为。接下来是我为了探索这个问题而进行的实验的细分:是否可以通过监督微调(SFT)和代理强化学习(RL)对小型开放权重模型进行后训练,以生成击败 Postgres 默认计划的 Postgres 查询计划?我们的问题的答案是肯定的。亮点包括: 在 4B 模型的 113 个连接密集型查询中实现了 44.7% 的延迟减少,该查询最初无法为其中 99 个生成查询计划 构建一个 Postgres 测量设备,最大限度地减少并发容器之间的 Linux 页面缓存争用噪音 设计一个自定义 GRPO 变体,用于在固有噪声环境中对 RL 部署进行评分 将 RL 拆分到两台机器上:vLLM 和租用的 2x H100 节点上的训练器以及四个在我的办公桌上运行的 Postgres 容器 在 600 个 GPT-6 Astra 代理轨迹上运行非策略蒸馏 让我们从头开始。在查询优化器内部考虑以下 IMDb 数据集片段: -- IMDb 标题(电影、连续剧、剧集等)[~1M 行] title ( id 整数 PRIMARY KEY , title text , Production_year 整数 , kind_id 整数 -- FK -> kind_type ) -- Movie <> 公司联结表 [~2M 行] movie_companies ( id 整数 PRIMARY KEY , movie_id 整数 , -- FK -> title.idcompany_idinteger , -- FK ->company_name.idcompany_type_idinteger , -- FK->company_type.idnotetext ) -- 公司名称、来源等 [~100k rows]company_name ( idintegerPRIMARYKEY , nametext ,country_codetext -- '[us]', '[jp]', ... ) -- 标题的公司角色查找表 [4行]company_type ( id integer PRIMARY KEY , kind text -- '制作公司', '发行商', ... ) -- 标题_is_的查找表 [7 rows] kind_type ( id integer PRIMARY KEY , kind text -- '电影', '电视剧', '剧集', ... ) 假设我正在尝试回答这个问题:“哪些日本公司在2000年代?”我们可以编写以下查询: SELECT cn 。 name , COUNT ( * ) AS 标题 FROM title AS t, movie_companies AS mc, company_name AS cn WHERE t 。 id=mc. movie_id 和 mc 。公司 ID = cn 。 id 和 cn 。国家/地区代码 = ' [jp] ' 和 t 。 Production_year 2000 年至 2009 年之间 GROUP BY cn 。名称 ORDER BY 标题 DESC LIMIT 10 ;运行此查询会输出 10 家日本公司以及 2000 年至 2009 年间与这些公司相关的头衔数量,按从高到低排序。但是 Postgres 是如何得到这些结果的呢? Postgres 为我们获取这些数据的路径并不是已定的结论,它与我们所说的选择性谓词(即 WHERE 子句中的过滤条件)密切相关。为了说明这一点,让我们想象一下没有日本公司过滤器或日期范围过滤器的相同查询: SELECT cn 。 name , COUNT ( * ) AS 标题 FROM title AS t, movie_companies AS mc, company_name AS cn WHERE t 。 id=mc. movie_id 和 mc 。公司 ID = cn 。 id GROUP BY cn .名称 ORDER BY 标题 DESC LIMIT 10 ; mc 只能通过 mc.company_id = cn.id 加入 cn,t 只能通过 t.id = mc.movie_id 加入 mc。如果我们考虑交换性,这些约束会产生两个连接树。从技术上讲,有八个连接树。在这种情况下,我们不这样做,因为它不会影响连接产生的关系的大小。有效的连接树: ⋈ ( company_name ⋈ movie_companies ) 与 title 的连接 ⋈ company_name 与 movie_companies t title 关系的连接 cn company_name 关系 mc movie_companies 关系 (cn ⋈ mc) ⋈ t ⋈ ( title ⋈ movie_companies ) 与 company_name 的连接 ⋈ title 与 movie_companies cn company_name 关系的连接t title 关系 mc movie_companies 关系 (t ⋈ mc) ⋈ cn 我们查询的两个连接树。较低的连接首先运行;结果是根连接的输入。表或查询结果的基数是它包含的行数。假设相关表具有以下基数:c
这篇文章对您有帮助吗?
订阅66必读
每日精选科技资讯,直达你的邮箱