Uploaded image for project: 'Core Server'
  1. Core Server
  2. SERVER-71717

Remove MakeObjSpec and model projections with 'keep/dropField' in sbe_stage_builder_projection.cpp

    • Type: Icon: Task Task
    • Resolution: Unresolved
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: None
    • Component/s: None
    • Query Execution
    • QE 2023-05-15
    • 10

      Consider the projection {_id: 0, "a.b.c": 1}. Currently, the projection stage builder will produce the following plan:

      [2] project [s6 = traverseP(s4, lambda(l1.0) {
          if isObject(l1.0)
          then makeBsonObj(MakeObjSpec(keep, [], ["a"]), l1.0, traverseP(getField(l1.0, "a"), lambda(l2.0) {
              if isObject(l2.0)
              then makeBsonObj(MakeObjSpec(keep, [], ["b"]), l2.0, traverseP(getField(l2.0, "b"), lambda(l3.0) {
                  if isObject(l3.0)
                  then makeBsonObj(MakeObjSpec(keep, ["c"], []), l3.0)
                  else Nothing
              }, Nothing))
              else Nothing
          }, Nothing))
          else Nothing
      }, Nothing)]
      [1] scan s4 s5 none none none none [] @"9b7f08cc-f7c3-4d13-957a-a824db1bb046" true false
      

      This plan makes use of the `makeBsonObj` vm instruction. Compare this to the plan generated by the optimizer, which uses keep/dropFields to implement the projection:

      plan : [2] project [s2 =
          let [
              l101.0 =
                  if isObject(s1)
                  then keepFields(s1, "a")
                  else s1
          ]
          in
              let [
                  l102.0 = traverseP(getField(l101.0, "a"), lambda(l103.0) {
                      let [
                          l104.0 =
                              let [
                                  l105.0 =
                                      if isObject(l103.0)
                                      then move(l103.0)
                                      else Nothing
                              ]
                              in
                                  if isObject(l105.0)
                                  then keepFields(move(l105.0), "b")
                                  else move(l105.0)
                      ]
                      in
                          let [
                              l106.0 = traverseP(getField(l104.0, "b"), lambda(l107.0) {
                                  let [
                                      l108.0 =
                                          if isObject(l107.0)
                                          then move(l107.0)
                                          else Nothing
                                  ]
                                  in
                                      if isObject(l108.0)
                                      then keepFields(move(l108.0), "c")
                                      else move(l108.0)
                              }, Nothing)
                          ]
                          in
                              if (exists(l106.0) || isObject(l104.0))
                              then setField(move(l104.0), "b", move(l106.0))
                              else move(l104.0)
                  }, Nothing)
              ]
              in
                  if (exists(l102.0) || isObject(l101.0))
                  then setField(move(l101.0), "a", move(l102.0))
                  else move(l101.0)
      

      This ticket tracks the work to replace MakeObjSpec with keep/dropFields and to remove MakeObjSpec

            Assignee:
            backlog-query-execution [DO NOT USE] Backlog - Query Execution
            Reporter:
            mihai.andrei@mongodb.com Mihai Andrei
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated: