Open-Source Wikis

/

MongoDB

/

Features

/

Query engine

mongodb/mongo

Query engine

The query engine plans, optimizes, and executes find/update/delete operations and the early stages of aggregation pipelines. Two engines coexist in the tree: the classic engine (src/mongo/db/exec/classic/) and the slot-based engine (SBE) (src/mongo/db/exec/sbe/). Planning, parsing, and shared infrastructure live under src/mongo/db/query/ (25+ subdirectories).

Purpose

Given a find (or one of its relatives) the engine must:

  1. Parse the query into a MatchExpression AST.
  2. Resolve indexes and collation.
  3. Produce candidate query plans.
  4. Pick the best plan (multi-planning) or read it from the plan cache.
  5. Execute the plan through a tree of PlanStage (classic) or PlanStage slot graph (SBE).
  6. Stream documents back to the client through a ClientCursor.

Pipeline of a find

graph TD
    Parse[Parse: find_command_request_test] --> CQ[CanonicalQuery]
    CQ --> Planner[QueryPlanner]
    Planner -->|candidate plans| MultiPlanner[MultiPlanner / cached plan]
    MultiPlanner -->|chosen plan| Builder[StageBuilder]
    Builder -->|classic| ClassicTree[Classic PlanStage tree]
    Builder -->|sbe| SbeTree[SBE PlanStage tree]
    ClassicTree --> Cursor[ClientCursor]
    SbeTree --> Cursor
    Cursor -->|getMore| Client

The split between classic and SBE happens at the stage builder step. SBE was introduced in 5.0 (Jul 2021) as an opt-in fast path; subsequent releases have progressively expanded the set of plans handed to SBE. The decision is made by query_planner_common.cpp and the SBE feature compatibility checks.

Major directories

src/mongo/db/query/
├── canonical_query.cpp         # The validated, optimized query.
├── query_planner.cpp           # Generates candidate plans.
├── plan_cache/                 # Cache from query shape -> winning plan.
├── plan_enumerator/            # Enumerates plan alternatives.
├── plan_ranking/               # Multi-planning to pick the best alternative.
├── stage_builder/              # Translates QuerySolution -> PlanStage tree.
├── compiler/                   # AST -> intermediate representation.
├── algebra/                    # Algebra over query operations.
├── client_cursor/              # ClientCursor and cursor manager.
├── collation/                  # Collation rules.
├── plan_cache.h                # Cache entry point.
├── query_settings/             # Per-query overrides (cluster-wide).
├── query_shape/                # Stable hash of a query's shape.
├── query_stats/                # Aggregated stats by query shape.
├── fle/                        # Queryable Encryption query rewrites.
├── search/                     # $search / Atlas Search integration.
├── timeseries/                 # Time-series query rewrites.
└── write_ops/                  # Update/delete planning.

src/mongo/db/exec/
├── classic/                    # Classic execution engine.
├── sbe/                        # Slot-based execution engine.
├── agg/                        # Aggregation execution.
├── express/                    # Fast-path execution for simple plans.
├── document_value/             # Document/Value model used by aggregation/SBE.
├── expression/                 # Expression evaluation.
├── matcher/                    # MatchExpression evaluation.
├── runtime_planners/           # Plan switching at runtime (SBE).
└── timeseries/                 # Bucket-aware execution.

Classic engine

The classic engine is a tree of PlanStage objects, each pulling documents from its child via work(). The shape is similar to a Volcano-style iterator pipeline:

LIMIT
└── SORT
    └── SKIP
        └── FETCH
            └── IXSCAN(index: {a:1})

Stages are in src/mongo/db/exec/classic/. The work() interface yields control on every iteration so the storage engine can cooperate with locking and read concern.

Slot-based engine (SBE)

SBE represents plans as a graph of PlanStages that exchange data via slots — typed registers carrying values across stages. SBE plans:

  • Avoid the per-document overhead of the classic engine for common shapes.
  • Use a vectorized expression compiler to evaluate predicates and projections.
  • Have a different runtime planner that can switch between trial plans dynamically.

SBE is in src/mongo/db/exec/sbe/. The expression compiler lives at src/mongo/db/exec/expression/.

Plan cache

Repeated queries with the same shape (same predicates, same projections, same sort) reuse the same plan from the plan cache (src/mongo/db/query/plan_cache/). Cache keys are computed by the query shape module (src/mongo/db/query/query_shape/), which hashes the structural form of a query while ignoring concrete values.

The cache stores:

  • The winning plan's QuerySolution.
  • Multi-planning statistics so it can be invalidated when its assumptions stop holding (e.g. data changes, indexes are dropped).
  • Per-shape PlanCacheEntrys keyed by collection and query shape.

db.collection.aggregate([{$planCacheStats: {}}]) is the operator-facing view.

Query stats and query settings

  • Query stats (src/mongo/db/query/query_stats/) aggregates per-shape statistics (latency, doc count, plan summary) across the cluster. Useful for "which queries are running on my cluster?".
  • Query settings (src/mongo/db/query/query_settings/) is a cluster-wide knob set per query shape — for example, force a particular index hint for all queries that match a given shape.

ClientCursor

A ClientCursor is the server-side state of an open cursor (a find or aggregation that hasn't been fully drained). The CursorManager (src/mongo/db/cursor_manager.h) tracks open cursors, enforces idle timeouts, and reaps abandoned cursors. The mongos has its own ClusterCursorManager (src/mongo/s/query/cluster_cursor_manager.h) for cursors that fan out across shards.

Key source files

File Purpose
src/mongo/db/query/canonical_query.cpp The validated query object.
src/mongo/db/query/query_planner.cpp Plan enumeration.
src/mongo/db/query/plan_cache/ Plan cache.
src/mongo/db/query/stage_builder/ QuerySolution → PlanStage tree.
src/mongo/db/exec/classic/ Classic execution stages.
src/mongo/db/exec/sbe/ Slot-based execution.
src/mongo/db/exec/agg/ Aggregation pipeline execution.
src/mongo/db/exec/express/ Fast-path execution for simple plans.
src/mongo/db/cursor_manager.h Server-side cursor lifecycle.

Integration points

  • The storage engine provides the RecordStore and SortedDataInterface the classic and SBE scans walk.
  • The aggregation pipeline uses the same Pipeline/DocumentSource framework but runs through the agg execution engine; some stages "lower" into SBE.
  • The shard role owns the acquireCollection API the planner uses to consult collection metadata.
  • The query stats and query settings systems span mongod and mongos.

Entry points for modification

Adding a new query language operator usually means a new MatchExpression subclass under src/mongo/db/matcher/, a parser entry, and a pair of executor implementations (classic + SBE). Plan-cache changes are concentrated in src/mongo/db/query/plan_cache/. New index types add a IndexAccessMethod and integrate via src/mongo/db/index/. The query_golden test suites pin plan output and require explicit acknowledgment when output changes.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Query engine – MongoDB wiki | Factory