summaryrefslogtreecommitdiff
path: root/src/mongo/db/query/query_planner_test.cpp
diff options
context:
space:
mode:
authorDavid Storch <david.storch@10gen.com>2015-05-29 19:15:19 -0400
committerDavid Storch <david.storch@10gen.com>2015-07-10 17:11:16 -0400
commit15c72c8570c63e2e6ba0a3d339a8286d0be604db (patch)
tree96cc37b3259e9ce7472132b8c414eb614317c037 /src/mongo/db/query/query_planner_test.cpp
parent9c63b79a8d5c8d19663850f9d668a3581dea77d5 (diff)
downloadmongo-15c72c8570c63e2e6ba0a3d339a8286d0be604db.tar.gz
SERVER-13732 rewrite contained $or queries to rooted $or in the SubplanStage
This allows queries with an $or contained within an explicit or implicit $and to be answered with more efficient plans. It also expands the use of the SubplanStage to include contained $or queries and therefore may reduce the number of plans considered for these queries.
Diffstat (limited to 'src/mongo/db/query/query_planner_test.cpp')
-rw-r--r--src/mongo/db/query/query_planner_test.cpp122
1 files changed, 122 insertions, 0 deletions
diff --git a/src/mongo/db/query/query_planner_test.cpp b/src/mongo/db/query/query_planner_test.cpp
index 4768eed4312..9950b295cc1 100644
--- a/src/mongo/db/query/query_planner_test.cpp
+++ b/src/mongo/db/query/query_planner_test.cpp
@@ -706,6 +706,128 @@ TEST_F(QueryPlannerTest, OrOfAnd6) {
" b: [[1,1,true,true], [5,5,true,true]]}}}]}}}}");
}
+// We do collapse OR of ANDs if branches of the OR plan are using identical index scans.
+TEST_F(QueryPlannerTest, RootedOrOfAndCollapseIndenticalScans) {
+ addIndex(BSON("a" << 1 << "b" << 1));
+ runQuery(fromjson("{$or: [{a:1, b:2}, {a:1, b:2}]}"));
+
+ assertNumSolutions(2U);
+ assertSolutionExists("{cscan: {dir: 1}}");
+ assertSolutionExists(
+ "{fetch: {filter: null, node: {ixscan: {pattern: {a: 1, b: 1}},"
+ "bounds: {a: [[1,1,true,true]], b: [[2,2,true,true]]},"
+ "filter: null}}}");
+}
+
+TEST_F(QueryPlannerTest, ContainedOrOfAndCollapseIndenticalScans) {
+ addIndex(BSON("a" << 1 << "b" << 1));
+ runQuery(fromjson("{c: 1, $or: [{a:1, b:2}, {a:1, b:2}]}"));
+
+ assertNumSolutions(2U);
+ assertSolutionExists("{cscan: {dir: 1}}");
+ assertSolutionExists(
+ "{fetch: {filter: {c: 1}, node: {ixscan: {pattern: {a: 1, b: 1}},"
+ "bounds: {a: [[1,1,true,true]], b: [[2,2,true,true]]},"
+ "filter: null}}}");
+}
+
+TEST_F(QueryPlannerTest, ContainedOrOfAndCollapseIndenticalScansWithFilter) {
+ addIndex(BSON("a" << 1 << "b" << 1));
+ runQuery(fromjson("{c: 1, $or: [{a:1, b:2}, {a:1, b:2, d:3}]}"));
+
+ assertNumSolutions(2U);
+ assertSolutionExists("{cscan: {dir: 1}}");
+ assertSolutionExists(
+ "{fetch: {filter: {c: 1}, node: {ixscan: {pattern: {a: 1, b: 1}},"
+ "bounds: {a: [[1,1,true,true]], b: [[2,2,true,true]]},"
+ "filter: null}}}");
+}
+
+TEST_F(QueryPlannerTest, ContainedOrOfAndCollapseIndenticalScansWithFilter2) {
+ addIndex(BSON("a" << 1 << "b" << 1));
+ runQuery(fromjson("{c: 1, $or: [{a:{$gte:1,$lte:1}, b:2}, {a:1, b:2, d:3}]}"));
+
+ assertNumSolutions(2U);
+ assertSolutionExists("{cscan: {dir: 1}}");
+ assertSolutionExists(
+ "{fetch: {filter: {c: 1}, node: {fetch: {filter: null, node: "
+ "{ixscan: {pattern: {a: 1, b: 1}},"
+ "bounds: {a: [[1,1,true,true]], b: [[2,2,true,true]]},"
+ "filter: null}}}}}");
+}
+
+TEST_F(QueryPlannerTest, ContainedOrOfAndCollapseIdenticalScansTwoFilters) {
+ addIndex(BSON("a" << 1 << "b" << 1));
+ runQuery(fromjson("{c: 1, $or: [{a:1, b:2, d:3}, {a:1, b:2, e:4}]}"));
+
+ assertNumSolutions(2U);
+ assertSolutionExists("{cscan: {dir: 1}}");
+ assertSolutionExists(
+ "{fetch: {filter: {c: 1}, node: {fetch: {filter: {$or:[{e:4},{d:3}]},"
+ "node: {ixscan: {pattern: {a: 1, b: 1}, filter: null,"
+ "bounds: {a: [[1,1,true,true]], b: [[2,2,true,true]]}}}}}}}");
+}
+
+TEST_F(QueryPlannerTest, RootedOrOfAndCollapseScansExistingOrFilter) {
+ addIndex(BSON("a" << 1 << "b" << 1));
+ runQuery(fromjson("{$or: [{a:1, b:2, $or: [{c:3}, {d:4}]}, {a:1, b:2, e:5}]}"));
+
+ assertNumSolutions(2U);
+ assertSolutionExists("{cscan: {dir: 1}}");
+ assertSolutionExists(
+ "{fetch: {filter: {$or: [{e:5},{c:3},{d:4}]}, node: {ixscan: "
+ "{filter: null, pattern: {a: 1, b: 1}, "
+ "bounds: {a: [[1,1,true,true]], b: [[2,2,true,true]]}}}}}");
+}
+
+TEST_F(QueryPlannerTest, RootedOrOfAndCollapseTwoScansButNotThird) {
+ addIndex(BSON("a" << 1 << "b" << 1));
+ addIndex(BSON("c" << 1 << "d" << 1));
+ runQuery(fromjson("{$or: [{a: 1, b: 2}, {c: 3, d: 4}, {a: 1, b: 2}]}"));
+
+ assertNumSolutions(2U);
+ assertSolutionExists("{cscan: {dir: 1}}");
+ assertSolutionExists(
+ "{fetch: {filter: null, node: {or: {nodes: ["
+ "{ixscan: {pattern: {a: 1, b: 1}, filter: null,"
+ "bounds: {a: [[1,1,true,true]], b: [[2,2,true,true]]}}},"
+ "{ixscan: {pattern: {c: 1, d: 1}, filter: null,"
+ "bounds: {c: [[3,3,true,true]], d: [[4,4,true,true]]}}}]}}}}");
+}
+
+TEST_F(QueryPlannerTest, RootedOrOfAndCollapseTwoScansButNotThirdWithFilters) {
+ addIndex(BSON("a" << 1 << "b" << 1));
+ addIndex(BSON("c" << 1 << "d" << 1));
+ runQuery(fromjson("{$or: [{a:1, b:2, e:5}, {c:3, d:4}, {a:1, b:2, f:6}]}"));
+
+ assertNumSolutions(2U);
+ assertSolutionExists("{cscan: {dir: 1}}");
+ assertSolutionExists(
+ "{fetch: {filter: null, node: {or: {nodes: ["
+ "{fetch: {filter: {$or: [{f:6},{e:5}]}, node: "
+ "{ixscan: {pattern: {a: 1, b: 1}, filter: null,"
+ "bounds: {a: [[1,1,true,true]], b: [[2,2,true,true]]}}}}},"
+ "{ixscan: {pattern: {c: 1, d: 1}, filter: null,"
+ "bounds: {c: [[3,3,true,true]], d: [[4,4,true,true]]}}}]}}}}");
+}
+
+TEST_F(QueryPlannerTest, RootedOrOfAndDontCollapseDifferentBounds) {
+ addIndex(BSON("a" << 1 << "b" << 1));
+ addIndex(BSON("c" << 1 << "d" << 1));
+ runQuery(fromjson("{$or: [{a: 1, b: 2}, {c: 3, d: 4}, {a: 1, b: 99}]}"));
+
+ assertNumSolutions(2U);
+ assertSolutionExists("{cscan: {dir: 1}}");
+ assertSolutionExists(
+ "{fetch: {filter: null, node: {or: {nodes: ["
+ "{ixscan: {pattern: {a: 1, b: 1}, filter: null,"
+ "bounds: {a: [[1,1,true,true]], b: [[2,2,true,true]]}}},"
+ "{ixscan: {pattern: {a: 1, b: 1}, filter: null,"
+ "bounds: {a: [[1,1,true,true]], b: [[99,99,true,true]]}}},"
+ "{ixscan: {pattern: {c: 1, d: 1}, filter: null,"
+ "bounds: {c: [[3,3,true,true]], d: [[4,4,true,true]]}}}]}}}}");
+}
+
// SERVER-13960: properly handle $or with a mix of exact and inexact predicates.
TEST_F(QueryPlannerTest, OrInexactWithExact) {
addIndex(BSON("name" << 1));