diff options
author | David Storch <david.storch@10gen.com> | 2014-04-17 10:19:46 -0400 |
---|---|---|
committer | Dan Pasette <dan@mongodb.com> | 2014-04-17 13:26:47 -0400 |
commit | eeef3c3ded2d8d55345af8b11041bafae8783958 (patch) | |
tree | 9007f5f8988e8accd56718c7d1cf55eac143fbb4 | |
parent | a093bfa703c4a63fb26b1bc16c0f6ae13261486e (diff) | |
download | mongo-eeef3c3ded2d8d55345af8b11041bafae8783958.tar.gz |
SERVER-13618 explode for sort tries reversing index scan direction
(cherry picked from commit ce52f313ca52759d606886641f44541bd7baf5bd)
-rw-r--r-- | src/mongo/db/query/planner_analysis.cpp | 12 | ||||
-rw-r--r-- | src/mongo/db/query/query_planner_test.cpp | 31 |
2 files changed, 42 insertions, 1 deletions
diff --git a/src/mongo/db/query/planner_analysis.cpp b/src/mongo/db/query/planner_analysis.cpp index 23a45b3942d..24441a7a811 100644 --- a/src/mongo/db/query/planner_analysis.cpp +++ b/src/mongo/db/query/planner_analysis.cpp @@ -300,7 +300,17 @@ namespace mongo { // See if it's the order we're looking for. BSONObj possibleSort = resultingSortBob.obj(); if (!desiredSort.isPrefixOf(possibleSort)) { - return false; + // We can't get the sort order from the index scan. See if we can + // get the sort by reversing the scan. + BSONObj reversePossibleSort = QueryPlannerCommon::reverseSortObj(possibleSort); + if (!desiredSort.isPrefixOf(reversePossibleSort)) { + // Can't get the sort order from the reversed index scan either. Give up. + return false; + } + else { + // We can get the sort order we need if we reverse the scan. + QueryPlannerCommon::reverseScans(isn); + } } // Do some bookkeeping to see how many ixscans we'll create total. diff --git a/src/mongo/db/query/query_planner_test.cpp b/src/mongo/db/query/query_planner_test.cpp index 692dcdf6ff6..eab24dec88d 100644 --- a/src/mongo/db/query/query_planner_test.cpp +++ b/src/mongo/db/query/query_planner_test.cpp @@ -1650,6 +1650,37 @@ namespace { "{fetch: {node: {ixscan: {pattern: {a: 1, b: 1, c:1, d:1}}}}}}}"); } + // SERVER-13618: test that exploding scans for sort works even + // if we must reverse the scan direction. + TEST_F(QueryPlannerTest, ExplodeMustReverseScans) { + addIndex(BSON("a" << 1 << "b" << 1 << "c" << 1 << "d" << 1)); + runQuerySortProj(fromjson("{a: {$in: [1, 2]}, b: {$in: [3, 4]}}"), + BSON("c" << -1), BSONObj()); + + assertNumSolutions(2U); + assertSolutionExists("{sort: {pattern: {c: -1}, limit: 0, node: {cscan: {dir: 1}}}}"); + assertSolutionExists("{fetch: {node: {mergeSort: {nodes: " + "[{ixscan: {pattern: {a:1, b:1, c:1, d:1}}}," + "{ixscan: {pattern: {a:1, b:1, c:1, d:1}}}," + "{ixscan: {pattern: {a:1, b:1, c:1, d:1}}}," + "{ixscan: {pattern: {a:1, b:1, c:1, d:1}}}]}}}}"); + } + + // SERVER-13618 + TEST_F(QueryPlannerTest, ExplodeMustReverseScans2) { + addIndex(BSON("a" << 1 << "b" << 1 << "c" << -1)); + runQuerySortProj(fromjson("{a: {$in: [1, 2]}, b: {$in: [3, 4]}}"), + BSON("c" << 1), BSONObj()); + + assertNumSolutions(2U); + assertSolutionExists("{sort: {pattern: {c: 1}, limit: 0, node: {cscan: {dir: 1}}}}"); + assertSolutionExists("{fetch: {node: {mergeSort: {nodes: " + "[{ixscan: {pattern: {a:1, b:1, c:-1}}}," + "{ixscan: {pattern: {a:1, b:1, c:-1}}}," + "{ixscan: {pattern: {a:1, b:1, c:-1}}}," + "{ixscan: {pattern: {a:1, b:1, c:-1}}}]}}}}"); + } + TEST_F(QueryPlannerTest, InWithSortAndLimitTrailingField) { addIndex(BSON("a" << 1 << "b" << -1 << "c" << 1)); runQuerySortProjSkipLimit(fromjson("{a: {$in: [1, 2]}, b: {$gte: 0}}"), |