目录
进入MongoDB中文手册(4.2版本)目录
对于查询,MongoDB查询优化器会根据可用索引选择并缓存最有效的查询计划。当查询计划程序评估候选的计划时,基于查询执行计划执行的“工作单元”(works)的数量评估出最有效的查询计划。
关联的计划缓存条目用于后续的具有相同查询形状(query shape)的查询。
1 计划的缓存条目状态(Cache Entry State)
从MongoDB 4.2开始,缓存条目与状态关联:
状态 | 描述 |
---|---|
Missing | 缓存中不存在此形状的条目。 对于查询,如果一个形状的缓存条目状态为 Missing: 1. 评估候选计划并选择优选的计划。 2. 所选计划将以Inactive状态和其works值添加到缓存中。 |
Inactive | 缓存中的条目是查询形状的占位符条目。也就是说,计划程序已经看到了形状并计算了其代价(works值)并存储为占位符条目,但查询形状不用于生成查询计划。 对于查询,如果形状的缓存条目状态时Inactive: 1. 评估候选计划并选择优选的计划。 2. 将所选计划的works值与Inactive条目的值进行比较。如果所选计划的works值为: * 小于或等于Inactive条目的值, 所选计划将替换占位符“Inactive”条目,并具有“ Active”状态。 如果在替换发生之前,“ Inactive”条目变为“ Active”(例如,由于另一个查询操作),则仅当新活动条目的works值大于所选计划时,才会替换新活动条目。 * 大于Inactive条目的数量, Inactive条目保留,但其works值增加。 |
Active | 缓存中的条目用于优选的计划。计划程序可以使用该条目来生成查询计划。 对于查询,如果形状的缓存条目状态为 Active: 1. Active条目用于生成查询计划。 2. 计划程序还评估条目的性能,如果条目的 works值不再符合选择标准,它将转换为Inactive状态。 |
有关触发对计划缓存进行更改的其他方案,请参阅计划缓存刷新。
1.1 查询计划和缓存信息
要查看给定查询的查询计划信息,可以使用 db.collection.explain()或cursor.explain()。
从MongoDB 4.2开始,您可以使用$planCacheStats 聚合阶段来查看集合的计划缓存信息。
1.2 计划缓存刷新
如果mongod 重新启动或关闭,查询计划缓存将不会保留。此外:
- 删除索引或集合这样的目录操作(Catalog operations)会清除计划缓存。
- 最近最少使用(LRU)缓存替换机制将清除最近最少访问的缓存条目,无论状态如何。
用户还可以:
- 使用PlanCache.clear()方法手动清除整个计划缓存 。
- 使用PlanCache.clearPlansByQuery()方法手动清除特定的计划缓存条目 。
2 queryHash和planCacheKey
2.1 queryHash
为了帮助识别具有相同查询形状的慢查询,从MongoDB 4.2开始,每个查询形状都与一个queryHash关联。queryHash是代表查询形状的一个hash,并且仅依赖于所述查询形状的十六进制字符串。
注意
与任何哈希函数一样,两个不同的查询形状可能会导致相同的哈希值。但是,不同查询形状之间不会发生哈希冲突。
2.2 planCacheKey
为了提供对查询计划缓存的更多了解,MongoDB 4.2引入了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 } } ) // 查询操作 1
db.foo.explain().find( { x: { $gt: 20 } } ) // 查询操作 2
给定这些查询,具有部分过滤器表达式(partial filter expression)的索引可以支持查询操作2,但不支持查询操作1。由于可用于支持查询操作1的索引不同于查询操作2,因此两个查询具有不同的 planCacheKey。
如果删除了一个索引,或者添加了新索引{ x: 1, a: 1 },则两个查询操作的都会更改planCacheKey。
2.3 可用性
queryHash和planCacheKey在用于:
- explain()输出字段: queryPlanner.queryHash和queryPlanner.planCacheKey;
- 记录慢查询时,分析器日志消息和诊断日志消息(即mongod / mongos日志消息);
- $planCacheStats聚合阶段(MongoDB 4.2中的新增功能);
- PlanCache.listQueryShapes()方法和planCacheListQueryShapes命令;
- PlanCache.getPlansByQuery() 方法和planCacheListPlans命令。
3 索引过滤器
索引过滤器确定优化器为查询形(query shape)状评估的索引 。查询形状由查询,排序和投影规范的组合而成。如果给定查询形状存在索引过滤器,那么优化器仅考虑过滤器中指定的那些索引。
当查询形状存在索引过滤器时,MongoDB将忽略 hint()。要查看MongoDB是否对查询形状应用了索引过滤器,请使用db.collection.explain()或cursor.explain()方法的indexFilterSet字段检查。
索引过滤器仅影响优化器评估的索引;优化器仍然可以选择将集合扫描作为给定的查询形状的优选的计划。
索引过滤器在服务器进程的持续时间内存在,并且在关闭后不会持续存在。MongoDB还提供了手动删除过滤器的命令。
因为索引过滤器会覆盖优化器和hint()方法的预期行为,所以请谨慎使用索引过滤器。
请参见planCacheListFilters, planCacheClearFilters和planCacheSetFilter。
也可以看看:索引策略。
进入MongoDB中文手册(4.2版本)目录