diff options
author | Mathias Stearn <mathias@10gen.com> | 2016-06-03 15:44:42 -0400 |
---|---|---|
committer | Mathias Stearn <mathias@10gen.com> | 2016-06-23 16:57:05 -0400 |
commit | 8a53668a313062adb9b4af48f5d76716e2ca58c8 (patch) | |
tree | 2ce360770f996deabd104fc4422875fd68e1ffe2 | |
parent | 5e85265e93f7515ae83481008410257c445e7459 (diff) | |
download | mongo-8a53668a313062adb9b4af48f5d76716e2ca58c8.tar.gz |
SERVER-24242 Stop applying the MatchExpression to OplogReplay queries after first match
-rw-r--r-- | src/mongo/db/exec/collection_scan.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/exec/collection_scan_common.h | 15 | ||||
-rw-r--r-- | src/mongo/db/query/get_executor.cpp | 8 |
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'. |