0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 01:21:03 +01:00
mongodb/db/queryoptimizer.h

180 lines
6.7 KiB
C
Raw Normal View History

2008-11-16 01:04:01 +01:00
/* queryoptimizer.h */
2008-11-14 22:19:47 +01:00
/**
* Copyright (C) 2008 10gen Inc.
2008-12-29 02:28:49 +01:00
*
2008-11-14 22:19:47 +01:00
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
2008-12-29 02:28:49 +01:00
*
2008-11-14 22:19:47 +01:00
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
2008-12-29 02:28:49 +01:00
*
2008-11-14 22:19:47 +01:00
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
2008-12-29 02:28:49 +01:00
#pragma once
2008-11-14 22:19:47 +01:00
2009-02-17 21:53:19 +01:00
#include "cursor.h"
#include "jsobj.h"
2009-02-24 20:14:45 +01:00
#include "queryutil.h"
2009-02-17 21:53:19 +01:00
2009-01-14 23:09:51 +01:00
namespace mongo {
2009-02-17 21:53:19 +01:00
2009-02-20 17:08:22 +01:00
class IndexDetails;
2010-03-11 04:44:51 +01:00
class IndexType;
2009-07-07 20:12:53 +02:00
class QueryPlan : boost::noncopyable {
public:
2009-07-07 20:12:53 +02:00
QueryPlan(NamespaceDetails *_d,
int _idxNo, // -1 = no index
const FieldRangeSet &fbs,
const BSONObj &order,
const BSONObj &startKey = BSONObj(),
2010-02-25 22:24:34 +01:00
const BSONObj &endKey = BSONObj() ,
string special="" );
2009-07-07 20:12:53 +02:00
/* If true, no other index can do better. */
2009-02-18 02:57:36 +01:00
bool optimal() const { return optimal_; }
/* ScanAndOrder processing will be required if true */
2009-02-18 02:57:36 +01:00
bool scanAndOrderRequired() const { return scanAndOrderRequired_; }
/* When true, the index we are using has keys such that it can completely resolve the
2009-02-18 02:57:36 +01:00
query expression to match by itself without ever checking the main object.
*/
bool exactKeyMatch() const { return exactKeyMatch_; }
/* If true, the startKey and endKey are unhelpful and the index order doesn't match the
requested sort order */
bool unhelpful() const { return unhelpful_; }
2009-02-19 19:58:22 +01:00
int direction() const { return direction_; }
2010-02-26 05:34:01 +01:00
auto_ptr< Cursor > newCursor( const DiskLoc &startLoc = DiskLoc() , int numWanted=0 ) const;
auto_ptr< Cursor > newReverseCursor() const;
BSONObj indexKey() const;
const char *ns() const { return fbs_.ns(); }
NamespaceDetails *nsd() const { return d; }
BSONObj query() const { return fbs_.query(); }
2009-05-13 17:10:29 +02:00
BSONObj simplifiedQuery( const BSONObj& fields = BSONObj() ) const { return fbs_.simplifiedQuery( fields ); }
const FieldRange &range( const char *fieldName ) const { return fbs_.range( fieldName ); }
2009-03-24 17:12:04 +01:00
void registerSelf( long long nScanned ) const;
// just for testing
BoundList indexBounds() const { return indexBounds_; }
2009-02-18 02:57:36 +01:00
private:
NamespaceDetails *d;
int idxNo;
const FieldRangeSet &fbs_;
2009-02-20 17:08:22 +01:00
const BSONObj &order_;
const IndexDetails *index_;
2009-02-18 02:57:36 +01:00
bool optimal_;
bool scanAndOrderRequired_;
bool exactKeyMatch_;
2009-02-19 19:58:22 +01:00
int direction_;
BoundList indexBounds_;
bool endKeyInclusive_;
bool unhelpful_;
2010-02-25 22:24:34 +01:00
string _special;
IndexType * _type;
};
// Inherit from this interface to implement a new query operation.
2009-12-21 18:26:16 +01:00
// The query optimizer will clone the QueryOp that is provided, giving
// each clone its own query plan.
2009-02-20 17:08:22 +01:00
class QueryOp {
public:
2009-02-24 21:45:18 +01:00
QueryOp() : complete_(), qp_(), error_() {}
2009-02-20 17:08:22 +01:00
virtual ~QueryOp() {}
2010-02-16 17:13:31 +01:00
/** this gets called after a query plan is set? ERH 2/16/10 */
virtual void init() = 0;
virtual void next() = 0;
2009-02-25 00:23:11 +01:00
virtual bool mayRecordPlan() const = 0;
2010-02-16 17:13:31 +01:00
/** @return a copy of the inheriting class, which will be run with its own
query plan.
*/
2009-02-20 17:08:22 +01:00
virtual QueryOp *clone() const = 0;
bool complete() const { return complete_; }
2009-02-24 21:45:18 +01:00
bool error() const { return error_; }
string exceptionMessage() const { return exceptionMessage_; }
2009-02-25 20:32:26 +01:00
const QueryPlan &qp() const { return *qp_; }
// To be called by QueryPlanSet::Runner only.
2009-02-25 00:23:11 +01:00
void setQueryPlan( const QueryPlan *qp ) { qp_ = qp; }
2009-02-24 21:45:18 +01:00
void setExceptionMessage( const string &exceptionMessage ) {
error_ = true;
exceptionMessage_ = exceptionMessage;
}
protected:
void setComplete() { complete_ = true; }
2009-02-20 17:08:22 +01:00
private:
bool complete_;
string exceptionMessage_;
const QueryPlan *qp_;
2009-02-24 21:45:18 +01:00
bool error_;
2009-02-20 17:08:22 +01:00
};
2009-05-28 21:22:24 +02:00
// Set of candidate query plans for a particular query. Used for running
// a QueryOp on these plans.
class QueryPlanSet {
public:
QueryPlanSet( const char *ns,
const BSONObj &query,
const BSONObj &order,
const BSONElement *hint = 0,
bool honorRecordedPlan = true,
const BSONObj &min = BSONObj(),
const BSONObj &max = BSONObj() );
int nPlans() const { return plans_.size(); }
2009-02-20 21:37:24 +01:00
shared_ptr< QueryOp > runOp( QueryOp &op );
template< class T >
shared_ptr< T > runOp( T &op ) {
return dynamic_pointer_cast< T >( runOp( static_cast< QueryOp& >( op ) ) );
}
const FieldRangeSet &fbs() const { return fbs_; }
BSONObj explain() const;
2009-02-26 21:53:33 +01:00
bool usingPrerecordedPlan() const { return usingPrerecordedPlan_; }
private:
void addOtherPlans( bool checkFirst );
typedef boost::shared_ptr< QueryPlan > PlanPtr;
typedef vector< PlanPtr > PlanSet;
void addPlan( PlanPtr plan, bool checkFirst ) {
if ( checkFirst && plan->indexKey().woCompare( plans_[ 0 ]->indexKey() ) == 0 )
return;
plans_.push_back( plan );
}
2009-02-25 16:48:41 +01:00
void init();
void addHint( IndexDetails &id );
struct Runner {
Runner( QueryPlanSet &plans, QueryOp &op );
2009-02-20 21:37:24 +01:00
shared_ptr< QueryOp > run();
2009-02-20 17:08:22 +01:00
QueryOp &op_;
QueryPlanSet &plans_;
2009-02-26 16:28:27 +01:00
static void initOp( QueryOp &op );
static void nextOp( QueryOp &op );
2009-02-20 17:08:22 +01:00
};
const char *ns;
2010-02-05 18:02:01 +01:00
BSONObj query_;
FieldRangeSet fbs_;
2009-02-20 17:08:22 +01:00
PlanSet plans_;
2009-02-25 16:48:41 +01:00
bool mayRecordPlan_;
bool usingPrerecordedPlan_;
BSONObj hint_;
BSONObj order_;
2009-03-24 17:12:04 +01:00
long long oldNScanned_;
2009-02-26 21:53:33 +01:00
bool honorRecordedPlan_;
BSONObj min_;
BSONObj max_;
};
2009-01-14 23:09:51 +01:00
// NOTE min, max, and keyPattern will be updated to be consistent with the selected index.
IndexDetails *indexDetailsForRange( const char *ns, string &errmsg, BSONObj &min, BSONObj &max, BSONObj &keyPattern );
2010-02-05 18:02:01 +01:00
inline bool isSimpleIdQuery( const BSONObj& query ){
return
strcmp( query.firstElement().fieldName() , "_id" ) == 0 &&
query.nFields() == 1 &&
query.firstElement().isSimpleType();
}
2009-01-14 23:09:51 +01:00
} // namespace mongo