课程视频
截至 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 | db.orders.find({ |
若有客户编号索引和金额索引,候选可以分别用一个索引定位,再检查另一个条件;集合扫描则顺序读取文档并求值。某些索引和查询结构还允许其他组合,候选生成受具体实现限制。
文档模型中字段可能缺失、为 null 或包含数组,索引也可能具有 multikey 等特征。计划替换需要保留对应查询语义,不能仅按 SQL 标量字段的直觉解释全部情况。
Round-Robin 竞赛怎样进行
论文中的试跑以 Round-Robin(轮转)方式推进:每个候选执行一个 work 步骤,记录是否产生结果、需要继续还是已经结束。达到试跑预算或终止条件后,系统比较评分。
1 | 建立候选 P1、P2、... |
这个过程可以在单线程上交错推进。多个候选同时参与竞赛,所指的是搜索和执行状态的并存;是否真的使用多个 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,可以看到另一条选择路径:先生成有限候选,再通过执行取得比较信息。它同样需要完整候选、适当评价指标和清楚的版本范围。
参考资料
First Past the Post: Evaluating Query Optimization in MongoDB (D. Tao et al., ADC 2024) (Primary)
ROME: Robust Query Optimization via Parallel Multi-Plan Execution (Z. Wei et al., SIGMOD 2024) (Optional)
