Avoid per-document Value construction of $geoNear point metadata when includeLocs is not requested

XMLWordPrintableJSON

    • Query Execution
    • Fully Compatible
    • v9.0
    • QE 2026-08-03
    • 200
    • None
    • None
    • None
    • None
    • None
    • None
    • None

      Overview

      In the classic execution engine, computeGeoNearDistance() (src/mongo/db/exec/classic/geo_near.cpp) constructs the point-metadata Value for every candidate document on the $geoNear hot path, even when the query did not request the point location (includeLocs / addPointMeta == false). This is wasted work on the per-document distance-computation path, which is one of the hottest parts of classic $geoNear execution.

      Background

      For each buffered candidate, computeGeoNearDistance() loops over the extracted geometries and, on every distance improvement, executes:

      if \(minDistance < 0 || nextDistance < minDistance\) {
          minDistance = nextDistance;
          minDistanceMetadata = Value{stored.element};   // owned copy, built unconditionally
      }
      

      The resulting minDistanceMetadata is only ever consumed later under if (nearParams.addPointMeta). When the stored geometry is a point (the common case), stored.element is a BSON array, and {{Value

      {BSONElement}

      }} recursively materializes an owned Value array per candidate document. For a $geoNear without includeLocs (e.g. distanceField-only queries, the default), this per-document Value construction is pure overhead.

      Proposed Change

      Track only the winning geometry during the loop (by pointer) and build the Value once, after the loop, and only when it is actually needed:

      • Replace the Value minDistanceMetadata accumulator with const StoredGeometry* minDistanceStored.
      • In the loop, set minDistanceStored = &stored; instead of copying into a Value.
      • At the end, keep {{setGeoNearPoint(Value {minDistanceStored\->element}

        )}} inside the existing if (nearParams.addPointMeta) guard.

      This is correctness-neutral (the emitted point metadata is unchanged) and is a general win for any $geoNear that does not request includeLocs.

      Prototype Data

      Prototyped and measured locally on the mongo-perf Aggregation.GeoNear2dSphere / Aggregation.GeoNear2d workloads (classic engine forced, Standalone inMemory, ARM), using interleaved A/B measurement (rebuild baseline -> measure -> rebuild prototype -> measure, back-to-back) to control for host performance drift observed over the session.

      Interleaved A/B, GeoNear2dSphere (ops/sec):
      * Round 1: baseline 232.3 -> prototype 289.3 (+24.5%)
      * Round 2: baseline 270.3 -> prototype 325.1 (+20.3%)

      GeoNear2d: approximately +6%.

      Correctness: a custom harness verified n<=100, the query predicate applied, distances ascending, and an exact result signature (ids + distances) identical to baseline for both 2d and 2dsphere.

      For comparison, three other per-document micro-optimizations prototyped in the same session were rejected:
      * absl::InlinedVector for the geometries vector: within noise (the std::set / per-geometry unique_ptr allocations dominate, not the vector).
      * Extracting only the near-field subtree instead of Document::toBson(): regression (-9% / -28%), because toBson() is already O(1) when the document is trivially convertible.
      * Caching RecordIdDeduplicator::getApproximateSize(): neutral (the call is already O(1)).

      Only this change (deferring the Value construction) produced a large, robust improvement.

      Scope of Work

      * src/mongo/db/exec/classic/geo_near.cpp — defer construction of the point-metadata Value in computeGeoNearDistance() until after the min-distance loop, guarded by addPointMeta.

      Acceptance Criteria

      * $geoNear point-metadata output (includeLocs) is unchanged.
      * No per-document Value construction occurs when addPointMeta == false.
      * Existing $geoNear correctness tests pass.

      Technical Notes

      * The prototype patch is attached to this ticket.
      * Since this is on the query hot path, a sys-perf patch is recommended before merge.

            Assignee:
            Jan Steemann
            Reporter:
            Jan Steemann
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: