summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/query/planner_access.cpp14
-rw-r--r--src/mongo/db/query/query_knobs.cpp2
-rw-r--r--src/mongo/db/query/query_knobs.h3
-rw-r--r--src/mongo/db/query/query_planner_test.cpp31
-rw-r--r--src/mongo/dbtests/plan_ranking.cpp13
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;