diff options
author | Irina Yatsenko <irina.yatsenko@mongodb.com> | 2022-05-05 20:40:59 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-05-05 22:53:15 +0000 |
commit | 2b8d2c722b4801e733f49ece64df07bae681e38d (patch) | |
tree | d129faf6ee715dfcc67037666147cf18c4b84abc /src/mongo | |
parent | 39a79932ad678b30b052e099323fd086679aa8a3 (diff) | |
download | mongo-2b8d2c722b4801e733f49ece64df07bae681e38d.tar.gz |
SERVER-66119 Avoid duplicated seek into index for local fields with nested arrays
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/query/sbe_stage_builder_lookup.cpp | 47 |
1 files changed, 27 insertions, 20 deletions
diff --git a/src/mongo/db/query/sbe_stage_builder_lookup.cpp b/src/mongo/db/query/sbe_stage_builder_lookup.cpp index c84d46ad592..665b0249925 100644 --- a/src/mongo/db/query/sbe_stage_builder_lookup.cpp +++ b/src/mongo/db/query/sbe_stage_builder_lookup.cpp @@ -473,18 +473,19 @@ std::pair<SlotId /* matched docs */, std::unique_ptr<sbe::PlanStage>> buildForei auto [foreignValueSlot, currentRootStage] = buildForeignKeysStream(foreignRecordSlot, foreignFieldName, nodeId, slotIdGenerator); - currentRootStage = makeLimitTree( - makeS<FilterStage<false>>(std::move(currentRootStage), - collatorSlot ? makeFunction("collIsMember", - makeVariable(*collatorSlot), - makeVariable(foreignValueSlot), - makeVariable(localKeysSetSlot)) - : makeFunction("isMember", - makeVariable(foreignValueSlot), - makeVariable(localKeysSetSlot)), - nodeId), - nodeId, - 1 /* take the foreign record once, even if multiple key values match */); + currentRootStage = + makeLimitTree(makeS<FilterStage<false /*IsConst*/>>( + std::move(currentRootStage), + collatorSlot ? makeFunction("collIsMember", + makeVariable(*collatorSlot), + makeVariable(foreignValueSlot), + makeVariable(localKeysSetSlot)) + : makeFunction("isMember", + makeVariable(foreignValueSlot), + makeVariable(localKeysSetSlot)), + nodeId), + nodeId, + 1 /* take the foreign record once, even if multiple key values match */); currentRootStage = makeS<LoopJoinStage>(std::move(foreignStage) /* outer */, std::move(currentRootStage) /* inner */, @@ -657,8 +658,9 @@ std::pair<SlotId, std::unique_ptr<sbe::PlanStage>> buildIndexJoinLookupStage( // - Array values: // a. If array is empty, [Undefined, Undefined] // b. If array is NOT empty, [array[0], array[0]] (point interval composed from the first - // array element) - // - All other types, single point interval [value, value] + // array element). This is needed to match {_id: 0, a: [[1, 2]]} to {_id: 0, b: [1, 2]}. + // - All other types, including array itself as a value, single point interval [value, value]. + // This is needed for arrays to match {_id: 1, a: [[1, 2]]} to {_id: 0, b: [[1, 2], 42]}. // // To implement these rules, we use the union stage: // union pointValue [ @@ -669,7 +671,7 @@ std::pair<SlotId, std::unique_ptr<sbe::PlanStage>> buildIndexJoinLookupStage( // coscan // , // // Branch 2 - // cfilter isArray(rawValue) + // filter isArray(rawValue) && !isMember(pointValue, localKeyValueSet) // project pointValue = fillEmpty( // getElement(rawValue, 0), // Undefined @@ -690,7 +692,7 @@ std::pair<SlotId, std::unique_ptr<sbe::PlanStage>> buildIndexJoinLookupStage( nodeId, nullBranchOutput, makeConstant(TypeTags::bsonUndefined, 0)); - nullBranch = makeS<FilterStage<true>>( + nullBranch = makeS<FilterStage<true /*IsConst*/>>( std::move(nullBranch), makeFunction("isNull", makeVariable(singleLocalValueSlot)), nodeId); auto arrayBranchOutput = slotIdGenerator.generate(); @@ -703,10 +705,15 @@ std::pair<SlotId, std::unique_ptr<sbe::PlanStage>> buildIndexJoinLookupStage( makeVariable(singleLocalValueSlot), makeConstant(TypeTags::NumberInt32, 0)), makeConstant(TypeTags::bsonUndefined, 0))); - arrayBranch = - makeS<FilterStage<true>>(std::move(arrayBranch), - makeFunction("isArray", makeVariable(singleLocalValueSlot)), - nodeId); + auto shouldProduceSeekForArray = + makeBinaryOp(EPrimBinary::logicAnd, + makeFunction("isArray", makeVariable(singleLocalValueSlot)), + makeUnaryOp(EPrimUnary::logicNot, + makeFunction("isMember", + makeVariable(arrayBranchOutput), + makeVariable(localKeysSetSlot)))); + arrayBranch = makeS<FilterStage<false /*IsConst*/>>( + std::move(arrayBranch), std::move(shouldProduceSeekForArray), nodeId); auto valueBranchOutput = slotIdGenerator.generate(); auto valueBranch = makeProjectStage(makeLimitCoScanTree(nodeId, 1), |