summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2016-06-03 15:44:42 -0400
committerMathias Stearn <mathias@10gen.com>2016-06-23 16:57:05 -0400
commit8a53668a313062adb9b4af48f5d76716e2ca58c8 (patch)
tree2ce360770f996deabd104fc4422875fd68e1ffe2
parent5e85265e93f7515ae83481008410257c445e7459 (diff)
downloadmongo-8a53668a313062adb9b4af48f5d76716e2ca58c8.tar.gz
SERVER-24242 Stop applying the MatchExpression to OplogReplay queries after first match
-rw-r--r--src/mongo/db/exec/collection_scan.cpp3
-rw-r--r--src/mongo/db/exec/collection_scan_common.h15
-rw-r--r--src/mongo/db/query/get_executor.cpp8
3 files changed, 19 insertions, 7 deletions
diff --git a/src/mongo/db/exec/collection_scan.cpp b/src/mongo/db/exec/collection_scan.cpp
index b130d128023..1e1e88ead01 100644
--- a/src/mongo/db/exec/collection_scan.cpp
+++ b/src/mongo/db/exec/collection_scan.cpp
@@ -171,6 +171,9 @@ PlanStage::StageState CollectionScan::returnIfMatches(WorkingSetMember* member,
++_specificStats.docsTested;
if (Filter::passes(member, _filter)) {
+ if (_params.stopApplyingFilterAfterFirstMatch) {
+ _filter = nullptr;
+ }
*out = memberID;
return PlanStage::ADVANCED;
} else {
diff --git a/src/mongo/db/exec/collection_scan_common.h b/src/mongo/db/exec/collection_scan_common.h
index f5766e0a0d6..712e56f1eac 100644
--- a/src/mongo/db/exec/collection_scan_common.h
+++ b/src/mongo/db/exec/collection_scan_common.h
@@ -40,24 +40,25 @@ struct CollectionScanParams {
BACKWARD = -1,
};
- CollectionScanParams()
- : collection(NULL), start(RecordId()), direction(FORWARD), tailable(false), maxScan(0) {}
-
// What collection?
// not owned
- const Collection* collection;
+ const Collection* collection = nullptr;
// isNull by default. If you specify any value for this, you're responsible for the RecordId
// not being invalidated before the first call to work(...).
RecordId start;
- Direction direction;
+ Direction direction = FORWARD;
// Do we want the scan to be 'tailable'? Only meaningful if the collection is capped.
- bool tailable;
+ bool tailable = false;
+
+ // Once the first matching document is found, assume that all documents after it must match.
+ // This is useful for oplog queries where we know we will see records ordered by the ts field.
+ bool stopApplyingFilterAfterFirstMatch = false;
// If non-zero, how many documents will we look at?
- size_t maxScan;
+ size_t maxScan = 0;
};
} // namespace mongo
diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp
index 4258c1f9ab9..b4e9ca6de89 100644
--- a/src/mongo/db/query/get_executor.cpp
+++ b/src/mongo/db/query/get_executor.cpp
@@ -597,6 +597,14 @@ StatusWith<unique_ptr<PlanExecutor>> getOplogStartHack(OperationContext* txn,
params.direction = CollectionScanParams::FORWARD;
params.tailable = cq->getQueryRequest().isTailable();
+ // If the query is just tsExpr, we know that every document in the collection after the first
+ // matching one must also match. To avoid wasting time running the match expression on every
+ // document to be returned, we tell the CollectionScan stage to stop applying the filter once it
+ // finds the first match.
+ if (cq->root() == tsExpr) {
+ params.stopApplyingFilterAfterFirstMatch = true;
+ }
+
unique_ptr<WorkingSet> ws = make_unique<WorkingSet>();
unique_ptr<CollectionScan> cs = make_unique<CollectionScan>(txn, params, ws.get(), cq->root());
// Takes ownership of 'ws', 'cs', and 'cq'.