diff options
-rw-r--r-- | src/mongo/db/query/planner_access.cpp | 14 | ||||
-rw-r--r-- | src/mongo/db/query/query_knobs.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/query/query_knobs.h | 3 | ||||
-rw-r--r-- | src/mongo/db/query/query_planner_test.cpp | 31 | ||||
-rw-r--r-- | src/mongo/dbtests/plan_ranking.cpp | 13 |
5 files changed, 61 insertions, 2 deletions
diff --git a/src/mongo/db/query/planner_access.cpp b/src/mongo/db/query/planner_access.cpp index b5f38a61626..ee514ddb187 100644 --- a/src/mongo/db/query/planner_access.cpp +++ b/src/mongo/db/query/planner_access.cpp @@ -38,6 +38,7 @@ #include "mongo/db/query/index_bounds_builder.h" #include "mongo/db/query/index_tag.h" #include "mongo/db/query/qlog.h" +#include "mongo/db/query/query_knobs.h" #include "mongo/db/query/query_planner.h" #include "mongo/db/query/query_planner_common.h" #include "mongo/util/log.h" @@ -871,7 +872,7 @@ namespace mongo { asn->children.swap(ixscanNodes); andResult = asn; } - else { + else if (internalQueryPlannerEnableHashIntersection) { AndHashNode* ahn = new AndHashNode(); ahn->children.swap(ixscanNodes); andResult = ahn; @@ -887,6 +888,17 @@ namespace mongo { } } } + else { + // We can't use sort-based intersection, and hash-based intersection is disabled. + // Clean up the index scans and bail out by returning NULL. + QLOG() << "Can't build index intersection solution: " + << "AND_SORTED is not possible and AND_HASH is disabled."; + + for (size_t i = 0; i < ixscanNodes.size(); i++) { + delete ixscanNodes[i]; + } + return NULL; + } } // Don't bother doing any kind of fetch analysis lite if we're doing it anyway above us. diff --git a/src/mongo/db/query/query_knobs.cpp b/src/mongo/db/query/query_knobs.cpp index 6b0503a4578..30efd8d15e9 100644 --- a/src/mongo/db/query/query_knobs.cpp +++ b/src/mongo/db/query/query_knobs.cpp @@ -56,6 +56,8 @@ namespace mongo { MONGO_EXPORT_SERVER_PARAMETER(internalQueryPlannerEnableIndexIntersection, bool, true); + MONGO_EXPORT_SERVER_PARAMETER(internalQueryPlannerEnableHashIntersection, bool, false); + MONGO_EXPORT_SERVER_PARAMETER(internalQueryPlanOrChildrenIndependently, bool, true); MONGO_EXPORT_SERVER_PARAMETER(internalQueryMaxScansToExplode, int, 200); diff --git a/src/mongo/db/query/query_knobs.h b/src/mongo/db/query/query_knobs.h index d12858264c7..913362558d7 100644 --- a/src/mongo/db/query/query_knobs.h +++ b/src/mongo/db/query/query_knobs.h @@ -51,6 +51,9 @@ namespace mongo { // Do we have ixisect on at all? extern bool internalQueryPlannerEnableIndexIntersection; + // Do we use hash-based intersection for rooted $and queries? + extern bool internalQueryPlannerEnableHashIntersection; + // // plan cache // diff --git a/src/mongo/db/query/query_planner_test.cpp b/src/mongo/db/query/query_planner_test.cpp index d6164250285..b329c0378b7 100644 --- a/src/mongo/db/query/query_planner_test.cpp +++ b/src/mongo/db/query/query_planner_test.cpp @@ -53,6 +53,7 @@ namespace { class QueryPlannerTest : public mongo::unittest::Test { protected: void setUp() { + internalQueryPlannerEnableHashIntersection = true; params.options = QueryPlannerParams::INCLUDE_COLLSCAN; addIndex(BSON("_id" << 1)); } @@ -4411,6 +4412,36 @@ namespace { assertNumSolutions(internalQueryEnumerationMaxOrSolutions); } + // Ensure that disabling AND_HASH intersection works properly. + TEST_F(QueryPlannerTest, IntersectDisableAndHash) { + bool oldEnableHashIntersection = internalQueryPlannerEnableHashIntersection; + + // Turn index intersection on but disable hash-based intersection. + internalQueryPlannerEnableHashIntersection = false; + params.options = QueryPlannerParams::NO_TABLE_SCAN | QueryPlannerParams::INDEX_INTERSECTION; + + addIndex(BSON("a" << 1)); + addIndex(BSON("b" << 1)); + addIndex(BSON("c" << 1)); + + runQuery(fromjson("{a: {$gt: 1}, b: 1, c: 1}")); + + // We should do an AND_SORT intersection of {b: 1} and {c: 1}, but no AND_HASH plans. + assertNumSolutions(4U); + assertSolutionExists("{fetch: {filter: {b: 1, c: 1}, node: {ixscan: " + "{pattern: {a: 1}, bounds: {a: [[1,Infinity,false,true]]}}}}}"); + assertSolutionExists("{fetch: {filter: {a:{$gt:1},c:1}, node: {ixscan: " + "{pattern: {b: 1}, bounds: {b: [[1,1,true,true]]}}}}}"); + assertSolutionExists("{fetch: {filter: {a:{$gt:1},b:1}, node: {ixscan: " + "{pattern: {c: 1}, bounds: {c: [[1,1,true,true]]}}}}}"); + assertSolutionExists("{fetch: {filter: {a:{$gt:1}}, node: {andSorted: {nodes: [" + "{ixscan: {filter: null, pattern: {b:1}}}," + "{ixscan: {filter: null, pattern: {c:1}}}]}}}}"); + + // Restore the old value of the has intersection switch. + internalQueryPlannerEnableHashIntersection = oldEnableHashIntersection; + } + // // Index intersection cases for SERVER-12825: make sure that // we don't generate an ixisect plan if a compound index is diff --git a/src/mongo/dbtests/plan_ranking.cpp b/src/mongo/dbtests/plan_ranking.cpp index 451c9907ffa..cbd44009ee9 100644 --- a/src/mongo/dbtests/plan_ranking.cpp +++ b/src/mongo/dbtests/plan_ranking.cpp @@ -52,6 +52,8 @@ namespace mongo { // How we access the external setParameter testing bool. extern bool internalQueryForceIntersectionPlans; + extern bool internalQueryPlannerEnableHashIntersection; + } // namespace mongo namespace PlanRankingTests { @@ -62,16 +64,21 @@ namespace PlanRankingTests { public: PlanRankingTestBase() : _internalQueryForceIntersectionPlans(internalQueryForceIntersectionPlans), + _enableHashIntersection(internalQueryPlannerEnableHashIntersection), _client(&_txn) { + // Run all tests with hash-based intersection enabled. + internalQueryPlannerEnableHashIntersection = true; + Client::WriteContext ctx(&_txn, ns); _client.dropCollection(ns); ctx.commit(); } virtual ~PlanRankingTestBase() { - // Restore external setParameter testing bool. + // Restore external setParameter testing bools. internalQueryForceIntersectionPlans = _internalQueryForceIntersectionPlans; + internalQueryPlannerEnableHashIntersection = _enableHashIntersection; } void insert(const BSONObj& obj) { @@ -150,6 +157,10 @@ namespace PlanRankingTests { // Restored at end of test invocation regardless of test result. bool _internalQueryForceIntersectionPlans; + // Holds the value of the global set parameter so it can be restored at the end + // of the test. + bool _enableHashIntersection; + scoped_ptr<MultiPlanStage> _mps; DBDirectClient _client; |