diff options
author | Ben Shteinfeld <ben.shteinfeld@mongodb.com> | 2022-07-27 19:05:38 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-07-27 21:44:16 +0000 |
commit | ded3208f1b21529a5bee4d322c1d16d858864587 (patch) | |
tree | 9e94157426852b5a6c9b75e38f1398d91b9a037f | |
parent | 0760d88c733011a7835b765368283e8dc2d5c144 (diff) | |
download | mongo-ded3208f1b21529a5bee4d322c1d16d858864587.tar.gz |
SERVER-68310 Filter out PartialSchemaRequirements which are unconstrained and avoid generating SargableNodes for nodes with empty PartialSchemaRequirements
-rw-r--r-- | src/mongo/db/query/optimizer/cascades/logical_rewriter.cpp | 23 | ||||
-rw-r--r-- | src/mongo/db/query/optimizer/logical_rewriter_optimizer_test.cpp | 36 |
2 files changed, 53 insertions, 6 deletions
diff --git a/src/mongo/db/query/optimizer/cascades/logical_rewriter.cpp b/src/mongo/db/query/optimizer/cascades/logical_rewriter.cpp index a7f83d11406..7a499b0ec18 100644 --- a/src/mongo/db/query/optimizer/cascades/logical_rewriter.cpp +++ b/src/mongo/db/query/optimizer/cascades/logical_rewriter.cpp @@ -655,16 +655,27 @@ static void convertFilterToSargableNode(ABT::reference_type node, return; } - for (const auto& [key, req] : conversion->_reqMap) { + // Remove any partial schema requirments which do not constrain their input + for (auto it = conversion->_reqMap.cbegin(); it != conversion->_reqMap.cend();) { uassert(6624111, "Filter partial schema requirement must contain a variable name.", - !key._projectionName.empty()); + !it->first._projectionName.empty()); uassert(6624112, "Filter partial schema requirement cannot bind.", - !req.hasBoundProjectionName()); - uassert(6624113, - "Filter partial schema requirement must have a range.", - !isIntervalReqFullyOpenDNF(req.getIntervals())); + !it->second.hasBoundProjectionName()); + if (isIntervalReqFullyOpenDNF(it->second.getIntervals())) { + it = conversion->_reqMap.erase(it); + } else { + ++it; + } + } + + // If the filter has no constraints after removing no-ops, then rewrite the filter with a + // predicate using the constant True. + if (conversion->_reqMap.empty()) { + ctx.addNode(make<FilterNode>(Constant::boolean(true), filterNode.getChild()), + isSubstitution); + return; } // If in substitution mode, disallow retaining original predicate. If in exploration mode, only diff --git a/src/mongo/db/query/optimizer/logical_rewriter_optimizer_test.cpp b/src/mongo/db/query/optimizer/logical_rewriter_optimizer_test.cpp index 3196110ac8c..62b5467c2fe 100644 --- a/src/mongo/db/query/optimizer/logical_rewriter_optimizer_test.cpp +++ b/src/mongo/db/query/optimizer/logical_rewriter_optimizer_test.cpp @@ -1492,5 +1492,41 @@ TEST(LogicalRewriter, SargableCE) { phaseManager.getMemo()); } +TEST(LogicalRewriter, RemoveNoopFilter) { + using namespace properties; + PrefixId prefixId; + + ABT scanNode = make<ScanNode>("ptest", "test"); + + ABT filterANode = make<FilterNode>( + make<EvalFilter>(make<PathGet>("a", make<PathCompare>(Operations::Gte, Constant::minKey())), + make<Variable>("ptest")), + std::move(scanNode)); + + ABT rootNode = make<RootNode>(properties::ProjectionRequirement{ProjectionNameVector{"ptest"}}, + std::move(filterANode)); + + OptPhaseManager phaseManager({OptPhaseManager::OptPhase::MemoSubstitutionPhase}, + prefixId, + {{{"test", {{}, {}}}}}, + DebugInfo::kDefaultForTests); + ABT latest = std::move(rootNode); + ASSERT_TRUE(phaseManager.optimize(latest)); + + ASSERT_EXPLAIN_V2( + "Root []\n" + "| | projections: \n" + "| | ptest\n" + "| RefBlock: \n" + "| Variable [ptest]\n" + "Filter []\n" + "| Const [true]\n" + "Scan [test]\n" + " BindBlock:\n" + " [ptest]\n" + " Source []\n", + latest); +} + } // namespace } // namespace mongo::optimizer |