课程视频

截至 2026 年 10 月 2 日,所给 B 站收藏夹收录到第 14 讲,官网 Schedule 未提供本讲视频链接。本页依据指定论文整理。

通过试跑观察候选计划

第 22 讲依据 First Past the Post: Evaluating Query Optimization in MongoDB整理。论文研究 MongoDB 7.0.1 的特定计划选择路径:轮流推进多个候选,观察它们完成的工作和产出的结果,再选择其中一条继续执行。

以下描述保留论文版本边界,避免把研究对象推广到所有 MongoDB 版本和执行引擎。FPTP(First Past the Post)是作者用于描述这种竞赛式选择的名称。

赞助商

一个查询有哪些访问候选

教学查询使用两个字段过滤:

1
2
3
4
db.orders.find({
customer_id: 42,
amount: { $gte: 100 }
});

若有客户编号索引和金额索引,候选可以分别用一个索引定位,再检查另一个条件;集合扫描则顺序读取文档并求值。某些索引和查询结构还允许其他组合,候选生成受具体实现限制。

文档模型中字段可能缺失、为 null 或包含数组,索引也可能具有 multikey 等特征。计划替换需要保留对应查询语义,不能仅按 SQL 标量字段的直觉解释全部情况。

Round-Robin 竞赛怎样进行

论文中的试跑以 Round-Robin(轮转)方式推进:每个候选执行一个 work 步骤,记录是否产生结果、需要继续还是已经结束。达到试跑预算或终止条件后,系统比较评分。

1
2
3
4
5
6
建立候选 P1、P2、...
重复轮转:
对每个活动候选调用一次 work
记录结果数量、工作次数和结束状态
达到试跑终止条件
计算评分,选择赢家继续执行

这个过程可以在单线程上交错推进。多个候选同时参与竞赛,所指的是搜索和执行状态的并存;是否真的使用多个 CPU 核心,要看具体实现。

Productivity 是工作单位上的产出

论文研究的评分包括基础分、Productivity、若干小额奖励以及完成奖励。核心比值是:

1
Productivity = 试跑产出的结果数 / work 次数

小额奖励涉及是否避免文档获取、阻塞排序或索引交集等,完整规则以论文为准。work 是执行器的逻辑工作单位,它的耗时可能因操作不同而变化。

例如一个索引路径需要获取索引条目并回表取文档,一次 work 的实际成本可能高于集合扫描读取下一个文档。若把两者都记为相近的工作次数,索引路径的产出比就可能显得过于有利。

主论文在 7.0.1 中分析了这种评分与真实时间的偏差,并指出候选集合中是否包含集合扫描也会影响选择。评分修正只有在存在合适候选时才可能生效。

同样的 Productivity 可以对应不同耗时

设候选 A 在 1000 次 work 中输出 100 行,候选 B 在 1000 次 work 中输出 80 行。A 的 Productivity 为 0.1,B 为 0.08,按这一信号 A 更有优势。再假设 A 每次 work 平均需要 20 微秒,B 需要 5 微秒,则试跑分别花费约 20 毫秒、5 毫秒。

单位时间的产出变为 A 每毫秒 5 行、B 每毫秒 16 行。这个教学例子说明 work 计量执行器的逻辑步骤,不同步骤的耗时需要另外测量。论文还讨论评分中的奖励与实际候选差异,完整评分需要与这些信号一起分析。

使用耗时计量也会引入计时噪声、缓存和预热差异,不能仅替换分母就保证所有场景正确。实验需要通过完整运行检验试跑信号是否能预测剩余工作,并分别控制存储布局与缓存状态。

早期表现怎样误导后续选择

假设候选 A 前 100 次 work 很快产生 50 行,候选 B 产生 20 行,A 更容易取得较高分。但如果 A 的早期输入恰好集中命中,而后续绝大多数输入不匹配,完整运行成本未必更低。

阻塞算子也会影响早期产出。排序或聚合可能先消耗输入,暂时不输出任何行,前期产出比无法完整表示最终收益。试跑越长,能看到的信息更多,多个候选的重复工作也越多。

因此竞赛式选择仍有观测代表性问题。它从真实执行取得信号,信号怎样计量、何时停止、覆盖哪些候选,都会影响质量。

索引的早期命中与阻塞输出

构造一个按索引顺序读取的候选。前 1000 个索引条目恰好集中满足第二个过滤条件,试跑很快产生很多结果;后面一百万条中命中极少。另一候选虽然早期产出较慢,却更均匀地定位全部有效文档。短试跑观察的是数据前缀,无法直接证明前缀具有整体代表性。

排序候选的情形不同:它可能需要先读取输入或完成足够的排序工作,才能产生第一行。试跑中的零产出包含两种可能:计划确实在做无效扫描,或者正在积累必要的阻塞状态。评分和停止规则需要认识这项差异。

如果查询只需少量结果,快速取得前几行本身又有实际价值。因此评价目标要明确,是首行延迟、满足 LIMIT 的时间,还是完整结果时间。用同一试跑信号服务不同目标,需要相应的策略和实验。

论文怎样检验选择效果

研究者对同一参数实例分别运行可用候选,用 hint 等机制约束计划,测量各自完整执行时间,再与优化器选择比较。主实验排除了缓存复用的影响,以集中研究计划评价机制。

两个指标需要分开:选择正确率表示选择最快候选的查询比例;性能损失表示被选计划耗时相对最快候选的倍率。大量微小误选与少量严重退化,对用户体验有不同意义。

1
性能损失 = 被选计划的执行时间 / 候选中最低执行时间

实验里的“最快”限定在测试的候选集合与运行环境内。重复测量、缓存状态、异常值处理和数据布局都会影响基准,论文给出了自己的实验设置。

作者还按两个过滤条件的选择率绘制计划区域与性能损失热图。这能显示哪些参数区域持续选错,以及错误边界是否对应访问路径切换。

计划缓存把决定带到后续查询

赢家可以进入计划缓存,后续相同查询形状可能复用它。这样减少了再次试跑的成本,也使一次选择的影响延续到后续参数。

相同形状的条件具有不同常量时,命中规模可能差很多,因此缓存复用和重新评估机制同样重要。本讲主论文主要隔离研究 FPTP 评价,不能直接由其结果推导所有缓存行为。

在二维选择率空间里解释误选区域

对前面的客户与金额条件,横轴设为客户过滤选择率,纵轴为金额过滤选择率。客户条件很稀疏时,客户索引可能占优;金额条件很稀疏时,金额索引可能占优;两者都宽松时,集合扫描可能更合适。实际边界还受字段相关性、回表与文档大小影响。

对每个参数点分别完整运行候选,可以得到“实际最快计划”区域;再记录 FPTP 选择的赢家,得到“试跑选择”区域。两张图的差异定位误选位置,性能损失热图则展示误选的严重程度。

若候选列表始终缺少集合扫描,那么对宽松条件区域,即使评分完全认识已有索引候选,也无法选择扫描。诊断因此先看候选生成是否覆盖合适路径,再看评价与试跑终止。候选不足和评分失真需要分别修正。

与 ROME 的关系

扩展阅读 ROME研究通过并行多计划执行提高查询鲁棒性。两者都使用真实运行信息缓解预测风险,但候选来源、资源分配、并行方式和终止条件各有设计。

阅读时先说明多个计划怎样共享或重复工作、何时保留赢家,再计算额外资源消耗。多计划机制的收益与试跑成本、候选差异和输入分布共同决定。

从本讲回看前面的 CE,可以看到另一条选择路径:先生成有限候选,再通过执行取得比较信息。它同样需要完整候选、适当评价指标和清楚的版本范围。

参考资料