文档菜单
文档首页
/
MongoDB 手册
/ /

查询计划

本页内容

  • 计划缓存条目状态
  • planCacheShapeHash
  • planCacheKey
  • 可用性

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

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

以下图表说明了查询规划器逻辑

A diagram of MongoDB's query planner logic.
点击放大

注意

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

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

状态
描述
缺失

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

对于查询,如果计划缓存查询形状的缓存条目状态为 缺失:

  1. 评估候选计划并选择获胜计划。

  2. 缓存为计划缓存查询形状创建一个条目,状态为 不活跃,该值量化了计划所需的工作量。

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

对于查询,如果形状的缓存条目状态为 不活跃:

  1. 评估候选计划并选择获胜计划。

  2. 所选计划量化计划所需工作量的值与 不活跃 条目的值进行比较。

    • 如果所选计划的值小于或等于 不活跃 条目的

      所选计划替换占位符 不活跃 条目,并具有 活动 状态。

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

    • 大于不活跃条目的
      不活跃条目仍然存在,但其量化计划所需工作量的值会增加。

缓存中的条目是为获胜的计划而设。规划器可以使用此条目来生成查询计划。

对于查询,如果形状的缓存条目状态为活跃:

使用活跃条目来生成查询计划。

规划器还会评估条目的性能,如果其量化计划所需工作量的值不再满足选择标准,则将其转换为不活跃状态。

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

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

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

如果mongod重启或关闭,则查询计划缓存不会持久化。此外

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

  • 最近最少使用(LRU)缓存替换机制会清除最少被访问的缓存条目,不论其状态。

用户还可以

提示

另请参阅

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

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

为了帮助识别具有相同查询缓存形状的慢查询,每个查询缓存形状都与一个查询哈希值相关联。查询缓存形状哈希是一个十六进制字符串,表示查询形状的哈希值,仅取决于查询形状。

注意

与任何哈希函数一样,两个不同的查询形状可能会导致相同的哈希值。但是,不同查询形状之间发生哈希碰撞的概率很低。

从MongoDB 8.0版本开始,原有的queryHash字段重命名为planCacheShapeHash。如果您使用的是早期版本的MongoDB,您将看到queryHash而不是planCacheShapeHash

为了提供更多关于查询计划缓存的见解,MongoDB提供了planCacheKey

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

注意

planCacheShapeHash不同,planCacheKey是查询形状和当前可用的索引的函数。也就是说,如果添加/删除可以支持查询形状的索引,则planCacheKey的值可能会更改,而planCacheShapeHash的值不会更改。

从MongoDB 8.0版本开始,原有的queryHash字段重命名为planCacheShapeHash。如果您使用的是早期版本的MongoDB,您将看到queryHash而不是planCacheShapeHash

例如,考虑一个具有以下索引的集合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 都将改变。

planCacheShapeHashplanCacheKey 可在以下位置找到:

使用 planCacheSetFilter 命令设置索引过滤器,以确定规划器为 查询形状 评估哪些索引。计划缓存查询形状由查询、排序和投影规范的组合组成。如果给定查询形状存在索引过滤器,则规划器仅考虑过滤器中指定的索引。

当查询缓存查询形状存在索引过滤器时,MongoDB会忽略hint()。要检查MongoDB是否为一个查询形状应用了索引过滤器,请检查indexFilterSet字段,这个字段可以在db.collection.explain()cursor.explain()方法中找到。

索引过滤器仅影响查询优化器评估哪些索引;对于给定的查询缓存查询形状,优化器仍然可能选择集合扫描作为最佳计划。

索引过滤器在服务器进程期间存在,并且在关闭后不会持久化。MongoDB还提供了一个命令来手动移除过滤器。

由于索引过滤器会覆盖查询优化器预期的行为以及hint()方法的行为,因此请谨慎使用索引过滤器。

从MongoDB 6.0开始,索引过滤器使用排序规则,这是使用planCacheSetFilter命令之前设置的。

从MongoDB 8.0开始,使用查询设置而不是添加索引过滤器。从MongoDB 8.0开始,索引过滤器已被弃用。

查询设置的功能比索引过滤器更多。此外,索引过滤器是不可持久的,并且您无法轻松地为所有集群节点创建索引过滤器。要添加查询设置并查看示例,请参阅setQuerySettings

返回

写性能