Skip to content

Commit 6ca9be7

Browse files
jameswahlinevergreen
authored andcommitted
SERVER-41872 PlanEnumerator AndAssignment::choices ordering not stable and is relevant to set of plans generated
1 parent dab2ae2 commit 6ca9be7

File tree

2 files changed

+70
-2
lines changed

2 files changed

+70
-2
lines changed

src/mongo/db/query/plan_enumerator.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -429,10 +429,16 @@ class PlanEnumerator {
429429
*/
430430
bool alreadyCompounded(const std::set<MatchExpression*>& ixisectAssigned,
431431
const AndAssignment* andAssignment);
432+
433+
struct CmpByIndexID {
434+
bool operator()(IndexID a, IndexID b) const {
435+
return a < b;
436+
}
437+
};
432438
/**
433-
* Output index intersection assignments inside of an AND node.
439+
* Maps from index id to the list of predicates assigned to that index.
434440
*/
435-
typedef stdx::unordered_map<IndexID, std::vector<MatchExpression*>> IndexToPredMap;
441+
typedef std::map<IndexID, std::vector<MatchExpression*>, CmpByIndexID> IndexToPredMap;
436442

437443
/**
438444
* Generate index intersection assignments given the predicate/index structure in idxToFirst

src/mongo/db/query/query_planner_tree_test.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2307,6 +2307,68 @@ TEST_F(QueryPlannerTest, ContainedOrPushdownIndexedExpr) {
23072307
assertSolutionExists("{cscan: {dir: 1}}}}");
23082308
}
23092309

2310+
// SERVER-41872 fixed a case where variable "choice" ordering in the PlanEnumerator memo could lead
2311+
// to different sets of solutions generated for the same input. This would occur in the case where
2312+
// we only enumerate a subset of possible plans due to reaching internal limits and enumerate plans
2313+
// in a non-stable order. With the fix for SERVER-41872, PlanEnumerator ordering is stable and
2314+
// expected to always return the same set of solutions for a given input.
2315+
TEST_F(QueryPlannerTest, SolutionSetStableWhenOrEnumerationLimitIsReached) {
2316+
params.options = QueryPlannerParams::NO_TABLE_SCAN;
2317+
addIndex(BSON("d" << 1));
2318+
addIndex(BSON("e" << 1));
2319+
addIndex(BSON("f" << 1));
2320+
addIndex(BSON("f" << 1 << "y" << 1));
2321+
addIndex(BSON("a" << 1));
2322+
addIndex(BSON("b" << 1));
2323+
addIndex(BSON("c" << 1));
2324+
addIndex(BSON("c" << 1 << "x" << 1));
2325+
2326+
runQueryAsCommand(
2327+
fromjson("{find: 'testns', filter: {$or: [{a: 1, b: 1, c: 1}, {d: 1, e: 1, f: 1}]}}"));
2328+
2329+
assertNumSolutions(10U);
2330+
2331+
assertSolutionExists(
2332+
"{or: {nodes: [{fetch: {filter: {b: {$eq: 1}, c: {$eq: 1} }, node: {ixscan: {pattern: {a: "
2333+
"1}}}}}, {fetch: {filter: {e: {$eq: 1}, f: {$eq: 1} }, node: {ixscan: {pattern: {d: "
2334+
"1}}}}}]}}");
2335+
assertSolutionExists(
2336+
"{or: {nodes: [{fetch: {filter: {a: {$eq: 1}, c: {$eq: 1} }, node: {ixscan: {pattern: {b: "
2337+
"1}}}}}, {fetch: {filter: {e: {$eq: 1}, f: {$eq: 1} }, node: {ixscan: {pattern: {d: "
2338+
"1}}}}}]}}");
2339+
assertSolutionExists(
2340+
"{or: {nodes: [{fetch: {filter: {a: {$eq: 1}, b: {$eq: 1} }, node: {ixscan: {pattern: {c: "
2341+
"1}}}}}, {fetch: {filter: {e: {$eq: 1}, f: {$eq: 1} }, node: {ixscan: {pattern: {d: "
2342+
"1}}}}}]}}");
2343+
assertSolutionExists(
2344+
"{or: {nodes: [{fetch: {filter: {a: {$eq: 1}, b: {$eq: 1} }, node: {ixscan: {pattern: {c: "
2345+
"1, x: 1}}}}}, {fetch: {filter: {e: {$eq: 1}, f: {$eq: 1} }, node: {ixscan: {pattern: {d: "
2346+
"1}}}}}]}}");
2347+
assertSolutionExists(
2348+
"{or: {nodes: [{fetch: {filter: {b: {$eq: 1}, c: {$eq: 1} }, node: {ixscan: {pattern: {a: "
2349+
"1}}}}}, {fetch: {filter: {d: {$eq: 1}, f: {$eq: 1} }, node: {ixscan: {pattern: {e: "
2350+
"1}}}}}]}}");
2351+
assertSolutionExists(
2352+
"{or: {nodes: [{fetch: {filter: {a: {$eq: 1}, c: {$eq: 1} }, node: {ixscan: {pattern: {b: "
2353+
"1}}}}}, {fetch: {filter: {d: {$eq: 1}, f: {$eq: 1} }, node: {ixscan: {pattern: {e: "
2354+
"1}}}}}]}}");
2355+
assertSolutionExists(
2356+
"{or: {nodes: [{fetch: {filter: {a: {$eq: 1}, b: {$eq: 1} }, node: {ixscan: {pattern: {c: "
2357+
"1}}}}}, {fetch: {filter: {d: {$eq: 1}, f: {$eq: 1} }, node: {ixscan: {pattern: {e: "
2358+
"1}}}}}]}}");
2359+
assertSolutionExists(
2360+
"{or: {nodes: [{fetch: {filter: {a: {$eq: 1}, b: {$eq: 1} }, node: {ixscan: {pattern: {c: "
2361+
"1, x: 1}}}}}, {fetch: {filter: {d: {$eq: 1}, f: {$eq: 1} }, node: {ixscan: {pattern: {e: "
2362+
"1}}}}}]}}");
2363+
assertSolutionExists(
2364+
"{or: {nodes: [{fetch: {filter: {b: {$eq: 1}, c: {$eq: 1} }, node: {ixscan: {pattern: {a: "
2365+
"1}}}}}, {fetch: {filter: {d: {$eq: 1}, e: {$eq: 1} }, node: {ixscan: {pattern: {f: "
2366+
"1}}}}}]}}");
2367+
assertSolutionExists(
2368+
"{or: {nodes: [{fetch: {filter: {a: {$eq: 1}, c: {$eq: 1} }, node: {ixscan: {pattern: {b: "
2369+
"1}}}}}, {fetch: {filter: {d: {$eq: 1}, e: {$eq: 1} }, node: {ixscan: {pattern: {f: "
2370+
"1}}}}}]}}");
2371+
}
23102372

23112373
} // namespace
23122374
} // namespace mongo

0 commit comments

Comments
 (0)