All Products
Search
Document Center

ApsaraDB for MongoDB:Query plans and query replanning

Last Updated:Mar 26, 2026

This topic describes how the MongoDB query planner works, how query plans are cached and evaluated, and what causes query replanning. It also explains how to identify replanning issues and provides solutions.

Query planner

For a given query, the MongoDB query planner selects and caches the most efficient query plan based on the available indexes. The following figure shows how the query planner works.

image

The evaluation of the most efficient query plan is based on the number of work units (works) performed by the query execution plan when the query planner evaluates candidate plans. A cached plan cache entry can be reused by any subsequent query with the same query shape.

Plan cache entry states

A plan cache entry can be in one of the following states:

State Description
Missing No entry exists in the plan cache. The query planner must evaluate candidate plans from scratch.
Inactive An entry exists in the plan cache with a recorded works value from a previous evaluation. The entry can transition to the Active state.
Active An entry exists in the plan cache and is used for matching queries. A winning plan in the Active state can transition back to the Inactive state if it is no longer efficient.

Plan cache behavior

The plan cache is stored entirely in memory and does not persist across restarts. The cache is cleared in the following situations:

  • The MongoDB database is restarted.

  • Collections or indexes are deleted.

The plan cache also has a size limit and follows the least recently used (LRU) cache replacement mechanism. Entries that are less frequently accessed are evicted from the cache over time.

Plan cache management commands

You can run the following commands to manage plan cache entries for a specific collection:

Command Description
db.<collection>.getPlanCache().clear() Clear the plan cache for a collection.
db.<collection>.getPlanCache().listQueryShapes() List all query shapes in the plan cache for a collection.
db.<collection>.getPlanCache().getPlansByQuery(...) Retrieve the cached query plan for a specific query.

Example of retrieving a cached query plan:

db.<collection>.getPlanCache().getPlansByQuery({"query": {"name": "testname"}, "sort": { "name": 1 })

queryHash and planCacheKey

MongoDB 4.2 and later introduces queryHash to identify query shapes. Each query shape is associated with a queryHash value. MongoDB 4.2 also introduces planCacheKey, which differs from queryHash in that it is a function of both the query shape and the available indexes for that shape. If indexes that can support the query shape are created or deleted, the planCacheKey value may change, but the queryHash value remains unchanged.

Example

Consider a collection with the following indexes and query shapes:

Indexes:

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

Query shapes:

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

The third index uses a partial filter expression that requires x > 10. Therefore, this index can support query operation 2 (x > 20) but not query operation 1 (x > 5). As a result, the two queries have different planCacheKey values. If a new index {x:1, a:1} is created, the planCacheKey values for both query operations change.

Query replanning

When data in a collection changes significantly, a previously cached query plan may no longer be optimal. The query planner detects this and replaces the plan to maintain query efficiency.

When you execute a query that matches the query shape of a cached plan, the query planner uses the cached plan directly instead of re-evaluating candidate plans. However, the query planner continuously monitors the execution efficiency of the cached plan. If the cached plan requires more than 10 times the expected number of work units, the query planner evicts the cached plan and re-evaluates all candidate plans. This process is called query replanning.

Impacts

  • Frequent query replanning can degrade query performance.

  • Excessive query replanning can lead to contention for mutex locks, resulting in high CPU utilization.

Identifying replanning

You may encounter the "replanned":true keyword in the slow query log. This keyword indicates that the query planner could not maintain a consistently efficient plan for a given query shape.

Example slow query log entry:

"replanned":true,"replanReason":"cached plan was less efficient than expected: expected trial execution to take X works but it took at least 10X works"

Solutions

The following solutions are organized from recommended long-term fixes to immediate mitigations and last-resort measures.

Recommended: optimize queries and indexes

Optimize your query statements and create effective indexes to prevent query replanning. Review and adjust your queries, available indexes, and document patterns rather than relying on hints or index filters.

Note

This is the preferred approach because it addresses the root cause of replanning rather than working around it.

Recommended: upgrade the MongoDB version

If the major version of your instance is MongoDB 4.2 or MongoDB 4.4, update the minor version to the latest available version. This can significantly reduce contention for mutex locks. You can also upgrade the major version to 5.0 or 6.0 to resolve these issues. For more information about the related kernel fix, see SERVER-40805.

For upgrade instructions, see Update the minor version of an instance and Upgrade the major version of an instance.

Clear the plan cache

Clear the plan cache and allow the query planner to select a more suitable query plan for your queries.

Use the hint() function

Use the hint() function in your application code to specify which index the query planner should use for queries that are subject to replanning. Example:

db.<collection>.find({a:"ABC"},{b:1,_id:0}).sort({c:1}).hint({ a:1, c:1, b:1} )
Note

When a hint is specified for a query, the query plan selected by the query planner does not take effect. The query uses the index specified in the hint instead.

Use index filters

Use index filters to restrict which indexes the query planner can consider for queries that are subject to replanning in your application code. Example:

// Set an index filter.
db.runCommand(
   {
      planCacheSetFilter: "<collection>",
      query: { a: "ABC" },
      projection: { b: 1, _id: 0 },
      sort: { c: 1 },
      indexes: [
         { a: 1, c: 1 , b: 1 }
      ]
   }
)
// Remove existing index filters.
db.runCommand(
   {
      planCacheClearFilters: "<collection>"
   }
)
Note
  • Index filters override the expected behavior of the query planner when selecting query plans.

  • If you specify both a hint and an index filter for a query, the index filter takes precedence over the hint. Use index filters with caution. For more information, see Index Filters.

Upgrade instance specifications

As a temporary measure, upgrade the instance specifications to alleviate database load. For more information, see Change the configurations of an instance.

Contact support

If the issues persist after you have tried the preceding solutions, Submit a ticket to contact technical support.

References