AnnouncementBuilt for unpredictable AI demand: Atlas Infinite and MongoDB 9.0 are here. Read more >  >>
AnnouncementMeet the intelligent data platform built for the AI era. Read more > >>
NewNow in public preview: Atlas Agent Engine, the secure way to run AI agents at scale. Read more > >>

Optimizing Document Lookup: Making Atlas Search and Vector Search Up to 5x Faster

November 11, 2026 ・ 4 min read

Sometimes the biggest performance gains come not from making core operations faster, but from eliminating unnecessary work surrounding them. That is exactly what we discovered while optimizing document lookup in MongoDB Atlas Search and Vector Search. By removing redundant query planning and execution overhead, we made search queries up to 5x faster without changing the underlying search algorithms.

When you run a $search or $vectorSearch query in MongoDB, two key stages work together to deliver the results. First, mongot, MongoDB's search process powered by Apache Lucene, executes the search query to identify and rank the most relevant documents. Then, mongod joins the search results with the corresponding BSON documents from the underlying collection using their _ids. The resulting documents can be further processed by additional aggregation pipeline stages before being returned to the application. Figure 1 illustrates this two-stage process:

Figure 1. Search execution in mongot and document materialization in mongod.

Diagram illustrating the two-stage search process in MongoDB: Stage 1 shows search execution in mongot using Apache Lucene to return ranked document IDs, and Stage 2 shows document materialization in mongod using $_internalSearchIdLookup to fetch the corresponding BSON documents.

This second stage, known as document materialization, is handled by an internal aggregation stage called $_internalSearchIdLookup. While search execution has been extensively optimized, we discovered that document lookup had become a significant performance bottleneck. For every matching document, the stage repeatedly constructed a new query plan and acquired collection resources, introducing substantial overhead for queries returning hundreds or thousands of results. In our profiling, approximately 30% of mongod CPU time was spent on query planning and collection acquisition, rather than retrieving documents.

To address this, we redesigned the document lookup execution path to eliminate redundant query planning, reuse execution plans, and amortize resource acquisition across multiple lookups. The result: up to 4.9x faster $search queries, 5.5x faster $vectorSearch queries, and approximately 2.75x higher throughput under concurrency.

These optimizations shipped in MongoDB 9.0, are enabled by default, and require no application changes. In this post, we'll explore how we identified the bottleneck, redesigned the execution path, and achieved these performance improvements.

The hidden cost of repeated query planning

Looking up a document by its _id is typically a fast operation in MongoDB, thanks to its efficient _id index. However, the original $_internalSearchIdLookup implementation constructed and executed a new aggregation sub-pipeline for every document returned by mongot, even though only the _id value changed:

JavaScript

For each document, MongoDB parsed the query, optimized the pipeline, constructed an execution plan, acquired collection resources, attached a cursor, executed the lookup, and released resources.

The problem was not the indexed document retrieval, but the repeated preparation work surrounding it. Even though the query structure was identical across lookups, MongoDB rebuilt the execution plan and reacquired collection resources for every document instead of reusing them. This overhead accumulated linearly with the number of results. For example, a search query returning 1,000 documents could trigger 1,000 separate cycles of query planning, collection acquisition, and resource cleanup. As result sets grew, the repeated preparation work became a substantial contributor to end-to-end search latency. Figure 2 illustrates this repeated execution overhead.

Figure 2. Repeated query planning and resource acquisition for each document lookup.

Diagram illustrating the original per-document lookup overhead, where each document ID triggers a repeated cycle of parsing the query, optimizing the pipeline, constructing an execution plan, acquiring collection resources, attaching a cursor, and releasing resources.

To quantify this overhead, we profiled representative Vector Search workloads. The results revealed that approximately 30% of mongod CPU time was spent on query plan construction and collection acquisition, rather than retrieving documents. This confirmed that the bottleneck was not primarily the underlying document reads, but the redundant work surrounding them.

Redesigning the document lookup execution path

To eliminate redundant lookup overhead, we redesigned $_internalSearchIdLookup around two key optimizations: reusing parameterized execution plans and batching document lookups to minimize resource acquisition overhead. Together, these changes allow MongoDB to retrieve thousands of documents without repeatedly rebuilding query plans or acquiring collection resources.

1. Reusing a parameterized SBE execution plan

The first major optimization was introducing SbeSingleDocumentLookupExecutor, built on MongoDB's Slot-Based Execution (SBE) engine. The key observation was simple: every document lookup follows the same query structure, and only the _id value changes. Instead of constructing a new execution plan for each document, the optimized executor builds the lookup plan once, caches it, and reuses it by rebinding the _id parameter for subsequent lookups.

For example, when retrieving 1,000 documents, the original implementation could construct 1,000 separate query plans. With the optimized executor, all 1,000 lookups can reuse a single parameterized plan.

This eliminates redundant query parsing, optimization, and plan construction, significantly reducing per-document execution overhead.

2. Batching document lookups to reuse collection resources

While plan reuse eliminates repeated query planning, acquiring and releasing collection resources for every document can still introduce substantial overhead. To address this, we introduced a reusable BatchedEnrichmentStage that buffers incoming search results and processes them within a shared resource scope. Instead of independently acquiring and releasing collection resources for every document, the optimized execution path reuses collection resources across multiple lookups within a batch, amortizing the acquisition and cleanup costs. For example, with 1,000 documents and a batch size of 100, collection resources can be acquired just 10 times instead of 1,000 times, i.e., once per batch rather than once per document. Although the number of document lookups still grows linearly with the result set size, batching significantly reduces the repeated resource management overhead.

Combined with SBE plan caching, this allows thousands of document lookups to share both an execution plan and collection resources, substantially reducing CPU overhead. The result is a more efficient document lookup architecture: build the execution plan once, reuse it across documents, and minimize repeated resource acquisition.

Figure 3 illustrates how the optimized approach eliminates redundant work by reusing execution plans and collection resources across document lookups.

Figure 3. Original per-document lookup vs. optimized batched lookup with shared execution plans.

Diagram comparing the original per-document lookup process—which repeatedly builds query plans and acquires collection resources for each document ID individually—with the optimized batched lookup process, which reuses a single SBE plan and shares collection resources across a batch of document IDs.

Performance results: End-to-end latency and throughput

As shown in Figure 4, both Atlas Search ($search) and Atlas Vector Search ($vectorSearch) achieved substantial reductions in end-to-end query latency across all evaluated result-set sizes (100, 1,000, and 10,000 documents). At 10,000 results, median latency dropped from approximately 2.6 seconds to 527 milliseconds for Atlas Search (4.9× faster) and from 3.1 seconds to 561 milliseconds for Atlas Vector Search (5.5× faster).

An important pattern emerges: the larger the result set, the greater the speedup. This is consistent with the underlying optimization. While search execution still incurs its own costs, eliminating repeated query planning and resource acquisition overhead becomes increasingly valuable as more documents are materialized.

Figure 4. End-to-end query latency improvements for Atlas Search and Atlas Vector Search in MongoDB 9.0.

Bar charts and tables comparing median query latency for Atlas Search ($search) and Atlas Vector Search ($vectorSearch) between Today's MongoDB and MongoDB 9.0 across result-set limits of 100, 1,000, and 10,000 documents, demonstrating latency reductions of up to 4.9x for Atlas Search and 5.5x for Atlas Vector Search.

Higher throughput under concurrency

Lower latency is only part of the story. We also evaluated performance under concurrent query execution. With 16 concurrent clients running a $search workload, the optimized implementation delivered:

  • Approximately 2.75x higher throughput

  • Approximately 3x lower median latency

These results demonstrate that the optimization does more than accelerate individual queries. By eliminating repeated query planning and resource acquisition, it reduces unnecessary CPU work per document lookup, allowing mongod to process more concurrent search requests with the same execution resources. The approximately 30% CPU overhead identified in our earlier profiling and the nearly 80% latency reduction observed in our benchmarks represent different measurements and workloads, rather than directly proportional improvements.

Real-world customer impact

To understand the potential impact on real-world workloads, we analyzed 163.8 million Atlas Vector Search executions across 610 customer clusters over 90 days. The analysis shows that larger result-set limits are used across a meaningful portion of the customer fleet. At least 40% of clusters execute queries with limits between 21 and 50, and at least 17% execute queries with limits above 100.

These workloads are particularly well-positioned to benefit from the document lookup optimizations, as eliminating repeated query planning and resource acquisition becomes increasingly valuable when more documents are retrieved.

Importantly, these improvements require no application changes. The optimized document lookup path is enabled by default in MongoDB 9.0.7. Applications do not need to rewrite queries, rebuild search indexes, or adopt new syntax. Existing $search and $vectorSearch pipelines can automatically benefit when running on supported configurations.

Faster search, without the extra work

This optimization began with a surprising observation: a simple _id lookup was spending a significant portion of its CPU budget preparing to execute rather than retrieving data. By replacing repeated aggregation planning with lightweight execution, introducing reusable batching infrastructure, and caching parameterized SBE plans, we removed a major source of overhead from Atlas Search and Vector Search. The result is up to 5.5× faster end-to-end queries in our benchmarks, along with substantial throughput improvements under concurrency.

More broadly, this work illustrates an important database engineering principle: sometimes the biggest performance gains come not from making the core operation faster, but from eliminating the unnecessary work surrounding it. This effort was made possible through collaboration across MongoDB’s Atlas Search Query, Query Execution, Query Integration, Database Integration and Observability, and Server Triage & Release teams. Special thanks to Denis Grebennicov from the Database Integration and Observability team for his significant contributions to this optimization effort.

megaphone
Next Steps

Ready to make your search queries faster? Upgrade to MongoDB 9.0 to take advantage of the optimized document lookup path. Existing $search and $vectorsearch pipelines can benefit automatically in supported configurations, without query rewrites or index rebuilds. 

MongoDB Resources