Docs 菜单
Docs 主页
/
MongoDB Manual
/ /

查询计划

在此页面上

  • 规划缓存条目状态
  • queryHash
  • planCacheKey
  • 可用性

对于任何给定的查询,在给定可用索引的情况下,MongoDB 查询规划器会选择并缓存最高效的查询计划。为了评估查询计划的效率,查询规划器会在试用期内运行所有候选计划。一般情况下,获胜计划是在试用期间产生最多结果同时执行最少工作量的查询计划。

关联的计划缓存条目用于具有相同查询形状的后续查询。

下图演示了查询规划器逻辑:

MongoDB 的查询规划器逻辑图。
点击放大

注意

使用 explain 会忽略所有现有的计划缓存条目,并阻止 MongoDB 查询计划器创建新的计划缓存条目。

每个计划缓存查询结构都与缓存中的三种状态之一相关联:

说明
缺失

缓存中不存在此形状的条目。

对于查询,如果查询结构的缓存条目状态为 Missing(缺失)

  1. 对候选计划进行评估,并选出获胜计划。

  2. 缓存会为处于非活动状态的查询结构创建一个条目,该条目的值可量化计划所需的工作量。

缓存中的条目是此形状的占位符条目。也就是说,规划器已查看形状,计算了一个值来量化计划所需的工作量,并存储了形状占位符条目,但查询结构用于生成查询计划。

对于查询,如果形状的缓存条目状态为 Active(非活动)

  1. 对候选计划进行评估,并选出获胜计划。

  2. 将量化计划所需工作量的所选计划的值与非活动条目的值进行比较。如果选定计划的值为:

    • 小于或等于非活动条目的值:

      所选计划取代了占位符“非活动”条目,并处于“活动”状态。

      如果在替换发生之前,非活动条目变为活动条目(例如,由于另一个查询操作),则新的活动条目只有在其量化的计划所需工作量值大于选定计划时才会被替换。

    • 大于非活动条目的值:
      非活动条目保持不变,但其量化计划所需工作量的值会递增。

缓存中的条目是面向获胜计划的。规划器可以使用此条目生成查询计划。

对于查询,如果查询结构的缓存条目状态为活动

活动条目用于生成查询计划。

规划器还会评估条目的性能,如果其用于量化计划所需工作量的值不再符合选择条件,则会转换为非活动状态。

有关触发计划缓存更改的其他场景,请参阅计划缓存刷新

要查看给定查询的查询计划信息,可以使用 db.collection.explain()cursor.explain()

要查看集合的计划缓存信息,可以使用 $planCacheStats 聚合阶段。

如果 mongod 重新启动或关闭,查询计划缓存将不复存在。此外:

  • 目录操作(如索引或集合删除)会清除计划缓存。

  • 最近最少使用 (LRU) 缓存替换机制会清除最近最少访问的缓存条目,而无论条目处于何种状态。

此外,用户还可:

提示

另请参阅:

从 MongoDB 5.0 开始,仅当所有集合的 plan caches 累计大小低于 0.5 GB 时,计划缓存才会保存完整的 plan cache 条目。当所有集合的 plan caches 累计大小超过此阈值时,计划缓存会存储额外的 plan cache 条目,但不会包含以下调试信息:

plan cache 条目的估计大小(以字节为单位)可在 $planCacheStats 的输出中找到。

为了帮助识别具有相同查询结构的慢速查询,每个查询结构都与一个 queryHash 相关联。queryHash 是一个十六进制字符串,表示查询结构的哈希值,并且仅依赖于查询结构。

注意

与任何哈希函数一样,两个不同的查询结构可能会产生相同的哈希值。但是,不同查询结构之间不太可能发生哈希冲突。

为了更深入地了解查询计划缓存,MongoDB 推出了 planCacheKey

planCacheKey 与此查询关联的计划缓存条目的键的哈希值。

注意

queryHash 不同,planCacheKey 是查询结构和该结构当前可用索引的函数。换言之,如果添加/删除可以支持该查询结构的索引,则 planCacheKey 值可能会更改,而 queryHash 值不会更改。

例如,考虑一个具有以下索引的集合 foo

db.foo.createIndex( { x: 1 } )
db.foo.createIndex( { x: 1, y: 1 } )
db.foo.createIndex( { x: 1, z: 1 }, { partialFilterExpression: { x: { $gt: 10 } } } )

对集合的以下查询具有相同的结构:

db.foo.explain().find( { x: { $gt: 5 } } ) // Query Operation 1
db.foo.explain().find( { x: { $gt: 20 } } ) // Query Operation 2

给定这些查询,带有部分筛选器表达式的索引可以支持查询操作 2,但支持查询操作 1。由于可用于支持查询操作 1 的索引与查询操作 2 的索引不同,因此,这两个查询具有不同的 planCacheKey

如果删除其中一个索引,或者,添加了新索引 { x: 1, a: 1 },则两个查询操作的 planCacheKey 将发生变化。

queryHashplanCacheKey 可用于:

索引筛选器由 planCacheSetFilter 命令,并确定计划器针对查询结构评估哪些索引。查询结构由查询、排序和投影规范的组合构成。如果给定查询结构存在索引筛选器,则计划器仅考虑筛选器中指定的索引。

当查询结构存在索引筛选器时,MongoDB 会忽略 hint()。要查看 MongoDB 是否为查询结构应用了索引筛选器,请检查 db.collection.explain()cursor.explain() 方法的 indexFilterSet 字段。

索引过滤器仅影响规划师评估哪些索引;规划师仍可选择集合扫描作为给定查询结构的获胜计划。

索引筛选器在服务器进程期间存在,而在关闭后会消失。MongoDB 还提供用于手动删除筛选器的命令。

由于索引筛选器会覆盖计划程序的预期行为以及 hint() 方法,因此请谨慎使用索引筛选器。

从 MongoDB 6.0 开始,索引筛选器会使用之前使用 planCacheSetFilter 命令设置的排序规则

后退

写入性能