summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Shteinfeld <ben.shteinfeld@mongodb.com>2022-07-27 19:05:38 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-07-27 21:44:16 +0000
commitded3208f1b21529a5bee4d322c1d16d858864587 (patch)
tree9e94157426852b5a6c9b75e38f1398d91b9a037f
parent0760d88c733011a7835b765368283e8dc2d5c144 (diff)
downloadmongo-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.cpp23
-rw-r--r--src/mongo/db/query/optimizer/logical_rewriter_optimizer_test.cpp36
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