diff options
author | David Storch <david.storch@10gen.com> | 2014-09-09 15:33:23 -0400 |
---|---|---|
committer | David Storch <david.storch@10gen.com> | 2014-09-17 09:37:26 -0400 |
commit | 775777b99c575edff05262140fbd529316aee939 (patch) | |
tree | 27159ce6583fca179afb48bd1fd05c1ed5c3173d | |
parent | ddce701ed775996f2a49fc949e26c5bcbc38fe84 (diff) | |
download | mongo-775777b99c575edff05262140fbd529316aee939.tar.gz |
SERVER-15279 disable hash-based index intersection by default
(cherry picked from commit 5e2b3c29b438f936eeb0a675e70e0131ab4c145a)
Conflicts:
src/mongo/dbtests/plan_ranking.cpp
-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 | 17 |
5 files changed, 64 insertions, 3 deletions
diff --git a/src/mongo/db/query/planner_access.cpp b/src/mongo/db/query/planner_access.cpp index 89d9284c979..ef946214fe0 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" @@ -851,7 +852,7 @@ namespace mongo { asn->children.swap(ixscanNodes); andResult = asn; } - else { + else if (internalQueryPlannerEnableHashIntersection) { AndHashNode* ahn = new AndHashNode(); ahn->children.swap(ixscanNodes); andResult = ahn; @@ -867,6 +868,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 877a76c33b4..b7ab829a738 100644 --- a/src/mongo/db/query/query_planner_test.cpp +++ b/src/mongo/db/query/query_planner_test.cpp @@ -52,6 +52,7 @@ namespace { class QueryPlannerTest : public mongo::unittest::Test { protected: void setUp() { + internalQueryPlannerEnableHashIntersection = true; params.options = QueryPlannerParams::INCLUDE_COLLSCAN; addIndex(BSON("_id" << 1)); } @@ -4075,6 +4076,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 02efa06321b..6124d4417b6 100644 --- a/src/mongo/dbtests/plan_ranking.cpp +++ b/src/mongo/dbtests/plan_ranking.cpp @@ -51,6 +51,8 @@ namespace mongo { // How we access the external setParameter testing bool. extern bool internalQueryForceIntersectionPlans; + extern bool internalQueryPlannerEnableHashIntersection; + } // namespace mongo namespace PlanRankingTests { @@ -62,14 +64,21 @@ namespace PlanRankingTests { class PlanRankingTestBase { public: - PlanRankingTestBase() : _internalQueryForceIntersectionPlans(internalQueryForceIntersectionPlans) { + PlanRankingTestBase() + : _internalQueryForceIntersectionPlans(internalQueryForceIntersectionPlans), + _enableHashIntersection(internalQueryPlannerEnableHashIntersection) { + + // Run all tests with hash-based intersection enabled. + internalQueryPlannerEnableHashIntersection = true; + Client::WriteContext ctx(ns); _client.dropCollection(ns); } virtual ~PlanRankingTestBase() { - // Restore external setParameter testing bool. + // Restore external setParameter testing bools. internalQueryForceIntersectionPlans = _internalQueryForceIntersectionPlans; + internalQueryPlannerEnableHashIntersection = _enableHashIntersection; } void insert(const BSONObj& obj) { @@ -160,6 +169,10 @@ namespace PlanRankingTests { // Holds the value of global "internalQueryForceIntersectionPlans" setParameter flag. // 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; }; DBDirectClient PlanRankingTestBase::_client; |