summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
authorAaron <aaron@10gen.com>2012-04-22 22:38:27 -0700
committerAaron <aaron@10gen.com>2012-04-24 19:56:27 -0700
commit82d92c3964f500776f4a9ba428bca2b88956006c (patch)
treed49741d43ae9a9f7a6d9b7413a26c1423370bd54 /src/mongo/db
parentfd4ed51a775999a4d9cfc8960cbd83f6c2733eb3 (diff)
downloadmongo-82d92c3964f500776f4a9ba428bca2b88956006c.tar.gz
Extract QueryPlanGenerator from QueryPlanSet.
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/queryoptimizer.cpp404
-rw-r--r--src/mongo/db/queryoptimizer.h101
-rw-r--r--src/mongo/db/queryoptimizercursorimpl.cpp3
3 files changed, 286 insertions, 222 deletions
diff --git a/src/mongo/db/queryoptimizer.cpp b/src/mongo/db/queryoptimizer.cpp
index 8f5cd632947..84dcd006bf9 100644
--- a/src/mongo/db/queryoptimizer.cpp
+++ b/src/mongo/db/queryoptimizer.cpp
@@ -53,6 +53,38 @@ namespace mongo {
}
return true;
}
+
+ // returns an IndexDetails * for a hint, 0 if hint is $natural.
+ // hint must not be eoo()
+ IndexDetails *parseHint( const BSONElement &hint, NamespaceDetails *d ) {
+ massert( 13292, "hint eoo", !hint.eoo() );
+ if( hint.type() == String ) {
+ string hintstr = hint.valuestr();
+ NamespaceDetails::IndexIterator i = d->ii();
+ while( i.more() ) {
+ IndexDetails& ii = i.next();
+ if ( ii.indexName() == hintstr ) {
+ return &ii;
+ }
+ }
+ }
+ else if( hint.type() == Object ) {
+ BSONObj hintobj = hint.embeddedObject();
+ uassert( 10112 , "bad hint", !hintobj.isEmpty() );
+ if ( !strcmp( hintobj.firstElementFieldName(), "$natural" ) ) {
+ return 0;
+ }
+ NamespaceDetails::IndexIterator i = d->ii();
+ while( i.more() ) {
+ IndexDetails& ii = i.next();
+ if( ii.keyPattern().woCompare(hintobj) == 0 ) {
+ return &ii;
+ }
+ }
+ }
+ uassert( 10113 , "bad hint", false );
+ return 0;
+ }
QueryPlan::QueryPlan( NamespaceDetails *d, int idxNo, const FieldRangeSetPair &frsp,
const FieldRangeSetPair *originalFrsp, const BSONObj &originalQuery,
@@ -385,221 +417,132 @@ doneCheckOrder:
_matcher.reset( new CoveredIndexMatcher( qp().originalQuery(), qp().indexKey() ) );
}
_init();
- }
-
- QueryPlanSet::QueryPlanSet( const char *ns, auto_ptr<FieldRangeSetPair> frsp,
- auto_ptr<FieldRangeSetPair> originalFrsp,
- const BSONObj &originalQuery,
- const BSONObj &order,
- const shared_ptr<const ParsedQuery> &parsedQuery,
- const BSONObj &hint,
- QueryPlanSet::RecordedPlanPolicy recordedPlanPolicy,
- const BSONObj &min, const BSONObj &max ) :
- _originalQuery( originalQuery ),
- _frsp( frsp ),
+ }
+
+ QueryPlanGenerator::QueryPlanGenerator( QueryPlanSet &qps,
+ auto_ptr<FieldRangeSetPair> originalFrsp,
+ const shared_ptr<const ParsedQuery> &parsedQuery,
+ const BSONObj &hint,
+ RecordedPlanPolicy recordedPlanPolicy,
+ const BSONObj &min,
+ const BSONObj &max ) :
+ _qps( qps ),
_originalFrsp( originalFrsp ),
- _mayRecordPlan( false ),
- _usingCachedPlan( false ),
- _hint( hint.getOwned() ),
- _order( order.getOwned() ),
_parsedQuery( parsedQuery ),
- _oldNScanned( 0 ),
+ _hint( hint.getOwned() ),
_recordedPlanPolicy( recordedPlanPolicy ),
_min( min.getOwned() ),
- _max( max.getOwned() ),
- _yieldSometimesTracker( 256, 20 ) {
- init();
+ _max( max.getOwned() ) {
}
- bool QueryPlanSet::hasMultiKey() const {
- for( PlanSet::const_iterator i = _plans.begin(); i != _plans.end(); ++i )
- if ( (*i)->isMultiKey() )
- return true;
- return false;
- }
-
-
- void QueryPlanSet::addHintedPlan( IndexDetails &id ) {
- if ( !_min.isEmpty() || !_max.isEmpty() ) {
- string errmsg;
- BSONObj keyPattern = id.keyPattern();
- // This reformats _min and _max to be used for index lookup.
- massert( 10365 , errmsg, indexDetailsForRange( _frsp->ns(), errmsg, _min, _max, keyPattern ) );
- }
- NamespaceDetails *d = nsdetails( _frsp->ns() );
- addPlan( newQueryPlan( d, d->idxNo( id ), _min, _max ) );
- }
-
- // returns an IndexDetails * for a hint, 0 if hint is $natural.
- // hint must not be eoo()
- IndexDetails *parseHint( const BSONElement &hint, NamespaceDetails *d ) {
- massert( 13292, "hint eoo", !hint.eoo() );
- if( hint.type() == String ) {
- string hintstr = hint.valuestr();
- NamespaceDetails::IndexIterator i = d->ii();
- while( i.more() ) {
- IndexDetails& ii = i.next();
- if ( ii.indexName() == hintstr ) {
- return &ii;
- }
- }
- }
- else if( hint.type() == Object ) {
- BSONObj hintobj = hint.embeddedObject();
- uassert( 10112 , "bad hint", !hintobj.isEmpty() );
- if ( !strcmp( hintobj.firstElementFieldName(), "$natural" ) ) {
- return 0;
- }
- NamespaceDetails::IndexIterator i = d->ii();
- while( i.more() ) {
- IndexDetails& ii = i.next();
- if( ii.keyPattern().woCompare(hintobj) == 0 ) {
- return &ii;
- }
- }
- }
- uassert( 10113 , "bad hint", false );
- return 0;
- }
-
- void QueryPlanSet::init() {
- DEBUGQO( "QueryPlanSet::init " << ns << "\t" << _originalQuery );
- _plans.clear();
- _usingCachedPlan = false;
-
- const char *ns = _frsp->ns();
+ void QueryPlanGenerator::addInitialPlans() {
+ const char *ns = _qps.frsp().ns();
NamespaceDetails *d = nsdetails( ns );
if ( !d ||
- !_frsp->matchPossible() ) {
- addUnindexedPlan( d );
+ !_qps.frsp().matchPossible() ) {
+ setSingleUnindexedPlan( d );
return;
}
-
+
BSONElement hint = _hint.firstElement();
if ( !hint.eoo() ) {
IndexDetails *id = parseHint( hint, d );
if ( id ) {
- addHintedPlan( *id );
+ setHintedPlan( *id );
}
else {
- uassert( 10366 , "natural order cannot be specified with $min/$max", _min.isEmpty() && _max.isEmpty() );
- addUnindexedPlan( d );
+ uassert( 10366, "natural order cannot be specified with $min/$max",
+ _min.isEmpty() && _max.isEmpty() );
+ setSingleUnindexedPlan( d );
}
return;
}
-
+
if ( !_min.isEmpty() || !_max.isEmpty() ) {
string errmsg;
BSONObj keyPattern;
IndexDetails *idx = indexDetailsForRange( ns, errmsg, _min, _max, keyPattern );
uassert( 10367 , errmsg, idx );
- addPlan( newQueryPlan( d, d->idxNo( *idx ), _min, _max ) );
+ _qps.setSinglePlan( newPlan( d, d->idxNo( *idx ), _min, _max ) );
return;
}
- DEBUGQO( "\t special : " << _frsp->getSpecial() );
- if ( _frsp->getSpecial().size() ) {
- string special = _frsp->getSpecial();
+ DEBUGQO( "\t special : " << _qps.frsp().getSpecial() );
+ if ( _qps.frsp().getSpecial().size() ) {
+ string special = _qps.frsp().getSpecial();
NamespaceDetails::IndexIterator i = d->ii();
while( i.more() ) {
int j = i.pos();
IndexDetails& ii = i.next();
const IndexSpec& spec = ii.getSpec();
- if ( spec.getTypeName() == special && spec.suitability( _originalQuery , _order ) ) {
- addPlan( newQueryPlan( d, j, BSONObj(), BSONObj(), special ) );
+ if ( spec.getTypeName() == special &&
+ spec.suitability( _qps.originalQuery(), _qps.order() ) ) {
+ _qps.setSinglePlan( newPlan( d, j, BSONObj(), BSONObj(), special ) );
return;
}
}
- uassert( 13038 , (string)"can't find special index: " + special + " for: " + _originalQuery.toString() , 0 );
+ uassert( 13038, (string)"can't find special index: " + special +
+ " for: " + _qps.originalQuery().toString(), false );
}
-
+
// If table scan is optimal or natural order requested.
- if ( ( _frsp->noNonUniversalRanges() && _order.isEmpty() ) ||
- ( !_order.isEmpty() && str::equals( _order.firstElementFieldName(), "$natural" ) ) ) {
- addUnindexedPlan( d );
+ if ( ( _qps.frsp().noNonUniversalRanges() && _qps.order().isEmpty() ) ||
+ ( !_qps.order().isEmpty() &&
+ str::equals( _qps.order().firstElementFieldName(), "$natural" ) ) ) {
+ setSingleUnindexedPlan( d );
return;
}
-
+
if ( _recordedPlanPolicy != Ignore ) {
- CachedQueryPlan best = QueryUtilIndexed::bestIndexForPatterns( *_frsp, _order );
+ CachedQueryPlan best = QueryUtilIndexed::bestIndexForPatterns( _qps.frsp(),
+ _qps.order() );
BSONObj bestIndex = best.indexKey();
- long long oldNScanned = best.nScanned();
- CandidatePlanCharacter bestPlanCharacter = best.planCharacter();
if ( !bestIndex.isEmpty() ) {
- QueryPlanPtr p;
- _oldNScanned = oldNScanned;
+ shared_ptr<QueryPlan> p;
if ( str::equals( bestIndex.firstElementFieldName(), "$natural" ) ) {
- p = newQueryPlan( d, -1 );
+ p = newPlan( d, -1 );
}
-
+
NamespaceDetails::IndexIterator i = d->ii();
while( i.more() ) {
int j = i.pos();
IndexDetails& ii = i.next();
if( ii.keyPattern().woCompare(bestIndex) == 0 ) {
- p = newQueryPlan( d, j );
+ p = newPlan( d, j );
}
}
-
+
massert( 10368 , "Unable to locate previously recorded index", p.get() );
if ( !p->unhelpful() &&
!( _recordedPlanPolicy == UseIfInOrder && p->scanAndOrderRequired() ) ) {
- _usingCachedPlan = true;
- _cachedPlanCharacter = bestPlanCharacter;
- addPlan( p );
+ _qps.setCachedPlan( p, best );
warnOnCappedIdTableScan();
return;
}
}
}
-
- addOtherPlans();
+
+ addFallbackPlans();
warnOnCappedIdTableScan();
}
-
- void QueryPlanSet::addPlan( QueryPlanPtr plan ) {
- // If _plans is nonempty, the new plan may be supplementing a recorded plan at the first
- // position of _plans. It must not duplicate the first plan.
- if ( nPlans() > 0 && plan->indexKey() == firstPlan()->indexKey() ) {
- return;
- }
- _plans.push_back( plan );
- }
-
- void QueryPlanSet::addFallbackPlans() {
- addOtherPlans();
- _mayRecordPlan = true;
- }
-
- void QueryPlanSet::addUnindexedPlan( NamespaceDetails *d ) {
- addPlan( newQueryPlan( d, -1 ) );
- }
- QueryPlanSet::QueryPlanPtr QueryPlanSet::newQueryPlan( NamespaceDetails *d, int idxNo,
- const BSONObj &min, const BSONObj &max,
- const string &special ) {
- QueryPlanPtr ret( new QueryPlan( d, idxNo, *_frsp, _originalFrsp.get(), _originalQuery,
- _order, _parsedQuery, min, max, special ) );
- return ret;
- }
-
- void QueryPlanSet::addOtherPlans() {
- const char *ns = _frsp->ns();
+ void QueryPlanGenerator::addFallbackPlans() {
+ const char *ns = _qps.frsp().ns();
NamespaceDetails *d = nsdetails( ns );
verify( d );
-
- PlanSet plans;
- QueryPlanPtr optimalPlan;
- QueryPlanPtr specialPlan;
+
+ vector<shared_ptr<QueryPlan> > plans;
+ shared_ptr<QueryPlan> optimalPlan;
+ shared_ptr<QueryPlan> specialPlan;
for( int i = 0; i < d->nIndexes; ++i ) {
-
- if ( !QueryUtilIndexed::indexUseful( *_frsp, d, i, _order ) ) {
+
+ if ( !QueryUtilIndexed::indexUseful( _qps.frsp(), d, i, _qps.order() ) ) {
continue;
}
-
- QueryPlanPtr p = newQueryPlan( d, i );
+
+ shared_ptr<QueryPlan> p = newPlan( d, i );
if ( p->impossible() ) {
- addPlan( p );
+ _qps.setSinglePlan( p );
return;
}
if ( p->optimal() ) {
@@ -616,8 +559,9 @@ doneCheckOrder:
}
}
}
+
if ( optimalPlan.get() ) {
- addPlan( optimalPlan );
+ _qps.setSinglePlan( optimalPlan );
// Record an optimal plan in the query cache immediately, with a small nscanned value
// that will be ignored.
optimalPlan->registerSelf
@@ -625,21 +569,139 @@ doneCheckOrder:
optimalPlan->scanAndOrderRequired() ) );
return;
}
- for( PlanSet::const_iterator i = plans.begin(); i != plans.end(); ++i ) {
- addPlan( *i );
- }
-
+
// Only add a special plan if no standard btree plans have been added. SERVER-4531
if ( plans.empty() && specialPlan ) {
- addPlan( specialPlan );
+ _qps.setSinglePlan( specialPlan );
return;
}
- addUnindexedPlan( d );
+ for( vector<shared_ptr<QueryPlan> >::const_iterator i = plans.begin(); i != plans.end();
+ ++i ) {
+ _qps.addCandidatePlan( *i );
+ }
+
+ _qps.addCandidatePlan( newPlan( d, -1 ) );
+ }
+
+ shared_ptr<QueryPlan> QueryPlanGenerator::newPlan( NamespaceDetails *d, int idxNo,
+ const BSONObj &min, const BSONObj &max,
+ const string &special ) const {
+ shared_ptr<QueryPlan> ret( new QueryPlan( d, idxNo, _qps.frsp(), _originalFrsp.get(),
+ _qps.originalQuery(), _qps.order(), _parsedQuery,
+ min, max, special ) );
+ return ret;
+ }
+
+ void QueryPlanGenerator::setSingleUnindexedPlan( NamespaceDetails *d ) {
+ _qps.setSinglePlan( newPlan( d, -1 ) );
+ }
+
+ void QueryPlanGenerator::setHintedPlan( IndexDetails &id ) {
+ if ( !_min.isEmpty() || !_max.isEmpty() ) {
+ string errmsg;
+ BSONObj keyPattern = id.keyPattern();
+ // This reformats _min and _max to be used for index lookup.
+ massert( 10365 , errmsg, indexDetailsForRange( _qps.frsp().ns(), errmsg, _min, _max,
+ keyPattern ) );
+ }
+ NamespaceDetails *d = nsdetails( _qps.frsp().ns() );
+ _qps.setSinglePlan( newPlan( d, d->idxNo( id ), _min, _max ) );
+ }
+
+ void QueryPlanGenerator::warnOnCappedIdTableScan() const {
+ // if we are doing a table scan on _id
+ // and it's a capped collection
+ // we warn as it's a common user error
+ // .system. and local collections are exempt
+ const char *ns = _qps.frsp().ns();
+ NamespaceDetails *d = nsdetails( ns );
+ if ( d &&
+ d->isCapped() &&
+ _qps.nPlans() == 1 &&
+ !_qps.firstPlan()->impossible() &&
+ !_qps.firstPlan()->indexed() &&
+ !_qps.firstPlan()->multikeyFrs().range( "_id" ).universal() ) {
+ if ( cc().isSyncThread() ||
+ str::contains( ns , ".system." ) ||
+ str::startsWith( ns , "local." ) ) {
+ // ok
+ }
+ else {
+ warning()
+ << "unindexed _id query on capped collection, "
+ << "performance will be poor collection: " << ns << endl;
+ }
+ }
+ }
- _mayRecordPlan = true;
+ QueryPlanSet::QueryPlanSet( const char *ns,
+ auto_ptr<FieldRangeSetPair> frsp,
+ auto_ptr<FieldRangeSetPair> originalFrsp,
+ const BSONObj &originalQuery,
+ const BSONObj &order,
+ const shared_ptr<const ParsedQuery> &parsedQuery,
+ const BSONObj &hint,
+ QueryPlanGenerator::RecordedPlanPolicy recordedPlanPolicy,
+ const BSONObj &min,
+ const BSONObj &max ) :
+ _generator( *this, originalFrsp, parsedQuery, hint, recordedPlanPolicy, min, max ),
+ _originalQuery( originalQuery ),
+ _frsp( frsp ),
+ _mayRecordPlan(),
+ _usingCachedPlan(),
+ _order( order.getOwned() ),
+ _oldNScanned( 0 ),
+ _yieldSometimesTracker( 256, 20 ) {
+ init();
+ }
+
+ bool QueryPlanSet::hasMultiKey() const {
+ for( PlanSet::const_iterator i = _plans.begin(); i != _plans.end(); ++i )
+ if ( (*i)->isMultiKey() )
+ return true;
+ return false;
+ }
+
+ void QueryPlanSet::init() {
+ DEBUGQO( "QueryPlanSet::init " << ns << "\t" << _originalQuery );
+ _plans.clear();
+ _usingCachedPlan = false;
+
+ _generator.addInitialPlans();
}
+ void QueryPlanSet::setSinglePlan( const QueryPlanPtr &plan ) {
+ addPlan( plan );
+ }
+
+ void QueryPlanSet::setCachedPlan( const QueryPlanPtr &plan,
+ const CachedQueryPlan &cachedPlan ) {
+ _usingCachedPlan = true;
+ _oldNScanned = cachedPlan.nScanned();
+ _cachedPlanCharacter = cachedPlan.planCharacter();
+ addPlan( plan );
+ }
+
+ void QueryPlanSet::addCandidatePlan( const QueryPlanPtr &plan ) {
+ addPlan( plan );
+ _mayRecordPlan = true;
+ }
+
+ void QueryPlanSet::addPlan( const QueryPlanPtr &plan ) {
+ // If _plans is nonempty, the new plan may be supplementing a recorded plan at the first
+ // position of _plans. It must not duplicate the first plan.
+ if ( nPlans() > 0 && plan->indexKey() == firstPlan()->indexKey() ) {
+ return;
+ }
+ _plans.push_back( plan );
+ }
+
+ void QueryPlanSet::addFallbackPlans() {
+ _generator.addFallbackPlans();
+ _mayRecordPlan = true;
+ }
+
bool QueryPlanSet::hasPossiblyExcludedPlans() const {
return _usingCachedPlan && ( nPlans() == 1 ) && !firstPlan()->optimal();
}
@@ -715,32 +777,6 @@ doneCheckOrder:
return bab.arr().jsonString();
}
- void QueryPlanSet::warnOnCappedIdTableScan() const {
- // if we are doing a table scan on _id
- // and it's a capped collection
- // we warn as it's a common user error
- // .system. and local collections are exempt
- const char *ns = _frsp->ns();
- NamespaceDetails *d = nsdetails( ns );
- if ( d &&
- d->isCapped() &&
- nPlans() == 1 &&
- !firstPlan()->impossible() &&
- !firstPlan()->indexed() &&
- !firstPlan()->multikeyFrs().range( "_id" ).universal() ) {
- if ( cc().isSyncThread() ||
- str::contains( ns , ".system." ) ||
- str::startsWith( ns , "local." ) ) {
- // ok
- }
- else {
- warning()
- << "unindexed _id query on capped collection, "
- << "performance will be poor collection: " << ns << endl;
- }
- }
- }
-
shared_ptr<QueryOp> MultiPlanScanner::iterateRunner( QueryOp &originalOp, bool retried ) {
if ( _runner ) {
@@ -956,7 +992,7 @@ doneCheckOrder:
const BSONObj &order,
const shared_ptr<const ParsedQuery> &parsedQuery,
const BSONObj &hint,
- QueryPlanSet::RecordedPlanPolicy recordedPlanPolicy,
+ QueryPlanGenerator::RecordedPlanPolicy recordedPlanPolicy,
const BSONObj &min,
const BSONObj &max ) :
_ns( ns ),
@@ -1167,7 +1203,7 @@ doneCheckOrder:
_nscanned( nscanned ),
_explainPlanInfo( explainPlanInfo ) {
_mps->clearRunner();
- _mps->setRecordedPlanPolicy( QueryPlanSet::UseIfInOrder );
+ _mps->setRecordedPlanPolicy( QueryPlanGenerator::UseIfInOrder );
if ( !ok() ) {
// If the supplied cursor is exhausted, try to advance it.
advance();
@@ -1377,7 +1413,7 @@ doneCheckOrder:
auto_ptr<FieldRangeSetPair> origFrsp( new FieldRangeSetPair( *frsp ) );
QueryPlanSet qps( ns, frsp, origFrsp, query, sort, shared_ptr<const ParsedQuery>(),
- BSONObj(), QueryPlanSet::UseIfInOrder );
+ BSONObj(), QueryPlanGenerator::UseIfInOrder );
QueryPlanSet::QueryPlanPtr qpp = qps.getBestGuess();
if( ! qpp.get() ) return shared_ptr<Cursor>();
diff --git a/src/mongo/db/queryoptimizer.h b/src/mongo/db/queryoptimizer.h
index 9c96794bc5a..a88f79d00d9 100644
--- a/src/mongo/db/queryoptimizer.h
+++ b/src/mongo/db/queryoptimizer.h
@@ -109,8 +109,8 @@ namespace mongo {
int _idxNo;
const FieldRangeSet &_frs;
const FieldRangeSet &_frsMulti;
- const BSONObj &_originalQuery;
- const BSONObj &_order;
+ const BSONObj _originalQuery;
+ const BSONObj _order;
shared_ptr<const ParsedQuery> _parsedQuery;
const IndexDetails * _index;
bool _optimal;
@@ -281,6 +281,44 @@ namespace mongo {
}
};
+ class QueryPlanSet;
+
+ class QueryPlanGenerator {
+ public:
+ /** Policies for utilizing recorded plans. */
+ typedef enum {
+ Ignore, // Ignore the recorded plan and try all candidate plans.
+ UseIfInOrder, // Use the recorded plan if it is properly ordered.
+ Use // Always use the recorded plan.
+ } RecordedPlanPolicy;
+
+ QueryPlanGenerator( QueryPlanSet &qps,
+ auto_ptr<FieldRangeSetPair> originalFrsp,
+ const shared_ptr<const ParsedQuery> &parsedQuery,
+ const BSONObj &hint,
+ RecordedPlanPolicy recordedPlanPolicy,
+ const BSONObj &min,
+ const BSONObj &max );
+ void addInitialPlans();
+ void addFallbackPlans();
+ private:
+ shared_ptr<QueryPlan> newPlan( NamespaceDetails *d,
+ int idxNo,
+ const BSONObj &min = BSONObj(),
+ const BSONObj &max = BSONObj(),
+ const string &special = "" ) const;
+ void setSingleUnindexedPlan( NamespaceDetails *d );
+ void setHintedPlan( IndexDetails &id );
+ void warnOnCappedIdTableScan() const;
+ QueryPlanSet &_qps;
+ auto_ptr<FieldRangeSetPair> _originalFrsp;
+ shared_ptr<const ParsedQuery> _parsedQuery;
+ BSONObj _hint;
+ RecordedPlanPolicy _recordedPlanPolicy;
+ BSONObj _min;
+ BSONObj _max;
+ };
+
/**
* A set of candidate query plans for a query. This class can return a best guess plan or run a
* QueryOp on all the plans.
@@ -290,27 +328,22 @@ namespace mongo {
typedef boost::shared_ptr<QueryPlan> QueryPlanPtr;
typedef vector<QueryPlanPtr> PlanSet;
- /** Policies for utilizing recorded plans. */
- typedef enum {
- Ignore, // Ignore the recorded plan and try all candidate plans.
- UseIfInOrder, // Use the recorded plan if it is properly ordered.
- Use // Always use the recorded plan.
- } RecordedPlanPolicy;
-
/**
- * @param originalFrsp - original constraints for this query clause; if null, frsp will be used.
+ * @param originalFrsp - original constraints for this query clause; if null, frsp will be
+ * used.
*/
QueryPlanSet( const char *ns,
- auto_ptr<FieldRangeSetPair> frsp,
- auto_ptr<FieldRangeSetPair> originalFrsp,
- const BSONObj &originalQuery,
- const BSONObj &order,
- const shared_ptr<const ParsedQuery> &parsedQuery =
- shared_ptr<const ParsedQuery>(),
- const BSONObj &hint = BSONObj(),
- RecordedPlanPolicy recordedPlanPolicy = Use,
- const BSONObj &min = BSONObj(),
- const BSONObj &max = BSONObj() );
+ auto_ptr<FieldRangeSetPair> frsp,
+ auto_ptr<FieldRangeSetPair> originalFrsp,
+ const BSONObj &originalQuery,
+ const BSONObj &order,
+ const shared_ptr<const ParsedQuery> &parsedQuery =
+ shared_ptr<const ParsedQuery>(),
+ const BSONObj &hint = BSONObj(),
+ QueryPlanGenerator::RecordedPlanPolicy recordedPlanPolicy =
+ QueryPlanGenerator::Use,
+ const BSONObj &min = BSONObj(),
+ const BSONObj &max = BSONObj() );
/** @return number of candidate plans. */
int nPlans() const { return _plans.size(); }
@@ -325,6 +358,7 @@ namespace mongo {
QueryPlanPtr getBestGuess() const;
const FieldRangeSetPair &frsp() const { return *_frsp; }
+ BSONObj originalQuery() const { return _originalQuery; }
BSONObj order() const { return _order; }
/** @return true if an active plan is in order. */
@@ -340,8 +374,11 @@ namespace mongo {
string toString() const;
+ void setSinglePlan( const QueryPlanPtr &plan );
+ void setCachedPlan( const QueryPlanPtr &plan, const CachedQueryPlan &cachedPlan );
+ void addCandidatePlan( const QueryPlanPtr &plan );
+
//for testing
- const FieldRangeSetPair *originalFrsp() const { return _originalFrsp.get(); }
bool modifiedKeys() const;
bool hasMultiKey() const;
@@ -395,30 +432,19 @@ namespace mongo {
};
private:
- void addOtherPlans();
+ void addPlan( const QueryPlanPtr &plan );
void addFallbackPlans();
- void addPlan( QueryPlanPtr plan );
- void addUnindexedPlan( NamespaceDetails *d );
- QueryPlanPtr newQueryPlan( NamespaceDetails *d, int idxNo, const BSONObj &min = BSONObj(),
- const BSONObj &max = BSONObj(), const string &special = "" );
void init();
- void addHintedPlan( IndexDetails &id );
- void warnOnCappedIdTableScan() const;
+ QueryPlanGenerator _generator;
BSONObj _originalQuery;
auto_ptr<FieldRangeSetPair> _frsp;
- auto_ptr<FieldRangeSetPair> _originalFrsp;
PlanSet _plans;
bool _mayRecordPlan;
bool _usingCachedPlan;
CandidatePlanCharacter _cachedPlanCharacter;
- BSONObj _hint;
BSONObj _order;
- shared_ptr<const ParsedQuery> _parsedQuery;
long long _oldNScanned;
- RecordedPlanPolicy _recordedPlanPolicy;
- BSONObj _min;
- BSONObj _max;
ElapsedTracker _yieldSometimesTracker;
};
@@ -431,7 +457,8 @@ namespace mongo {
const shared_ptr<const ParsedQuery> &parsedQuery =
shared_ptr<const ParsedQuery>(),
const BSONObj &hint = BSONObj(),
- QueryPlanSet::RecordedPlanPolicy recordedPlanPolicy = QueryPlanSet::Use,
+ QueryPlanGenerator::RecordedPlanPolicy recordedPlanPolicy =
+ QueryPlanGenerator::Use,
const BSONObj &min = BSONObj(),
const BSONObj &max = BSONObj() );
@@ -474,7 +501,7 @@ namespace mongo {
/** Clear the runner member. */
void clearRunner();
- void setRecordedPlanPolicy( QueryPlanSet::RecordedPlanPolicy recordedPlanPolicy ) {
+ void setRecordedPlanPolicy( QueryPlanGenerator::RecordedPlanPolicy recordedPlanPolicy ) {
_recordedPlanPolicy = recordedPlanPolicy;
}
@@ -549,7 +576,7 @@ namespace mongo {
scoped_ptr<OrRangeGenerator> _org; // May be null in certain non $or query cases.
auto_ptr<QueryPlanSet> _currentQps;
int _i;
- QueryPlanSet::RecordedPlanPolicy _recordedPlanPolicy;
+ QueryPlanGenerator::RecordedPlanPolicy _recordedPlanPolicy;
BSONObj _hint;
bool _tableScanned;
shared_ptr<QueryOp> _baseOp;
diff --git a/src/mongo/db/queryoptimizercursorimpl.cpp b/src/mongo/db/queryoptimizercursorimpl.cpp
index 100f23e5931..3cc87c61ceb 100644
--- a/src/mongo/db/queryoptimizercursorimpl.cpp
+++ b/src/mongo/db/queryoptimizercursorimpl.cpp
@@ -781,7 +781,8 @@ namespace mongo {
void CursorGenerator::setMultiPlanScanner() {
_mps.reset( new MultiPlanScanner( _ns, _query, _order, _parsedQuery, hint(),
- explain() ? QueryPlanSet::Ignore : QueryPlanSet::Use,
+ explain() ? QueryPlanGenerator::Ignore :
+ QueryPlanGenerator::Use,
min(), max() ) );
}