Unify docs/keys examined statistics for update operations between regular and express executors

XMLWordPrintableJSON

    • Type: Bug
    • Resolution: Fixed
    • Priority: Major - P3
    • 9.0.0-rc0
    • Affects Version/s: None
    • Component/s: None
    • None
    • Query Execution
    • Fully Compatible
    • ALL
    • QE 2026-03-30
    • 200
    • None
    • None
    • None
    • None
    • None
    • None
    • None

      If the update operation runs into a write conflict, it will be retried: we will be forced to read the index and the document again.

      In PlanExecutorImpl it is handled externally: classic UpdateStage will just throw WriteConflict exception:

      https://github.com/mongodb/mongo/blob/ba61be9030691d74f50a8faa5f2bd6755de85f8d/src/mongo/db/exec/classic/update_stage.cpp#L480

      This exception will be caught by writeConflictRetry function:

      https://github.com/mongodb/mongo/blob/ba61be9030691d74f50a8faa5f2bd6755de85f8d/src/mongo/db/commands/query_cmd/find_and_modify.cpp#L738

      Because of this, the PlanExecutor that threw the exception will be destroyed and it's statistics are discarded.

      Here is an example "Slow query" log:

      {<..>,"msg":"Slow query","attr":{,"command":{"q":{"a":5},"u":{"$inc":{"u":1},"$push":{"updates":"a"}},"multi":false,"upsert":false},"planSummary":"IXSCAN { a: 1 }","keysExamined":1,"docsExamined":1,"nMatched":1,"nModified":1,"writeConflicts":4,<..>,"durationMillis":4}}

      However, if the same happens in PlanExecutorExpress, it handles the error internally and retries inside the same executor, so the statistics are kept intact:

      https://github.com/mongodb/mongo/blob/ba61be9030691d74f50a8faa5f2bd6755de85f8d/src/mongo/db/exec/express/plan_executor_express.cpp#L114

      {<..>,"msg":"Slow query","attr":{<..>,"command":{"q":{"_id":5},"u":{"$inc":{"u":1},"$push":{"updates":"_id"}},"multi":false,"upsert":false},"planSummary":"EXPRESS_IXSCAN { _id: 1 },EXPRESS_UPDATE","keysExamined":5,"docsExamined":5,"nMatched":1,"writeConflicts":4,<..>,"durationMillis":7}}

      I think the behavior of EXPRESS executor is just a side effect of optimization, but it is actually nice and reflect the performance of the operation better than regular PlanExecutor.

      We should consider which behavior we prefer and make it the same across express and regular executors.

            Assignee:
            Ivan Fefer (Inactive)
            Reporter:
            Ivan Fefer (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            10 Start watching this issue

              Created:
              Updated:
              Resolved: