summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Boros <ian.boros@mongodb.com>2021-05-27 17:08:35 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-06-01 17:42:46 +0000
commit90eb445e58124ed8b6b46a048834bffe350dad4c (patch)
treecc24fb680e254f1e4eff5946b51b7b924af8d561
parentabda02c1aa43b6ce053eb8857d1724dceee43fd2 (diff)
downloadmongo-90eb445e58124ed8b6b46a048834bffe350dad4c.tar.gz
SERVER-57225 Prevent top-level AND optimization from being used for ANDs with many children
-rw-r--r--jstests/core/big_predicate.js20
-rw-r--r--src/mongo/db/query/sbe_stage_builder_filter.cpp7
2 files changed, 25 insertions, 2 deletions
diff --git a/jstests/core/big_predicate.js b/jstests/core/big_predicate.js
new file mode 100644
index 00000000000..d9d140b31d8
--- /dev/null
+++ b/jstests/core/big_predicate.js
@@ -0,0 +1,20 @@
+/**
+ * Test that a query containing an AND with a lot of clauses can be answered.
+ */
+(function() {
+"use strict";
+
+const coll = db.big_predicate;
+coll.drop();
+
+let filter = {};
+for (let i = 0; i < 2500; ++i) {
+ filter["field" + i] = 123;
+}
+
+assert.commandWorked(coll.insert({foo: 1}));
+assert.commandWorked(coll.insert(filter));
+
+assert.eq(coll.find(filter).itcount(), 1);
+assert.commandWorked(coll.explain().find(filter).finish());
+})();
diff --git a/src/mongo/db/query/sbe_stage_builder_filter.cpp b/src/mongo/db/query/sbe_stage_builder_filter.cpp
index 0cdccc4323a..cedb52a3f5b 100644
--- a/src/mongo/db/query/sbe_stage_builder_filter.cpp
+++ b/src/mongo/db/query/sbe_stage_builder_filter.cpp
@@ -80,6 +80,7 @@ namespace mongo::stage_builder {
namespace {
struct MatchExpressionVisitorContext;
+const size_t kMaxChildrenForTopLevelAndOptimization = 25;
/**
* Output of the tree can come from two places:
@@ -131,7 +132,8 @@ struct MatchExpressionVisitorContext {
// If the root node is an $and, store it in 'topLevelAnd'.
// TODO: SERVER-50673: Revisit how we implement the top-level $and optimization.
- if (root->matchType() == MatchExpression::AND) {
+ if (root->matchType() == MatchExpression::AND &&
+ root->numChildren() <= kMaxChildrenForTopLevelAndOptimization) {
topLevelAnd = root;
}
}
@@ -165,7 +167,8 @@ struct MatchExpressionVisitorContext {
// If the root node is an $and, store it in 'topLevelAnd'.
// TODO: SERVER-50673: Revisit how we implement the top-level $and optimization.
- if (root->matchType() == MatchExpression::AND) {
+ if (root->matchType() == MatchExpression::AND &&
+ root->numChildren() <= kMaxChildrenForTopLevelAndOptimization) {
topLevelAnd = root;
}
}