1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
/* queryoptimizer.h */
/**
* Copyright (C) 2008 10gen Inc.
*
* 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.
*
* 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.
*
* 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/>.
*/
#pragma once
#include "cursor.h"
#include "jsobj.h"
#include "queryutil.h"
namespace mongo {
class IndexDetails;
class IndexType;
class QueryPlan : boost::noncopyable {
public:
QueryPlan(NamespaceDetails *_d,
int _idxNo, // -1 = no index
const FieldRangeSet &fbs,
const BSONObj &order,
const BSONObj &startKey = BSONObj(),
const BSONObj &endKey = BSONObj() ,
string special="" );
/* If true, no other index can do better. */
bool optimal() const { return optimal_; }
/* ScanAndOrder processing will be required if true */
bool scanAndOrderRequired() const { return scanAndOrderRequired_; }
/* When true, the index we are using has keys such that it can completely resolve the
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_; }
int direction() const { return direction_; }
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(); }
BSONObj simplifiedQuery( const BSONObj& fields = BSONObj() ) const { return fbs_.simplifiedQuery( fields ); }
const FieldRange &range( const char *fieldName ) const { return fbs_.range( fieldName ); }
void registerSelf( long long nScanned ) const;
// just for testing
BoundList indexBounds() const { return indexBounds_; }
private:
NamespaceDetails *d;
int idxNo;
const FieldRangeSet &fbs_;
const BSONObj &order_;
const IndexDetails *index_;
bool optimal_;
bool scanAndOrderRequired_;
bool exactKeyMatch_;
int direction_;
BoundList indexBounds_;
bool endKeyInclusive_;
bool unhelpful_;
string _special;
IndexType * _type;
};
// Inherit from this interface to implement a new query operation.
// The query optimizer will clone the QueryOp that is provided, giving
// each clone its own query plan.
class QueryOp {
public:
QueryOp() : complete_(), qp_(), error_() {}
virtual ~QueryOp() {}
/** this gets called after a query plan is set? ERH 2/16/10 */
virtual void init() = 0;
virtual void next() = 0;
virtual bool mayRecordPlan() const = 0;
/** @return a copy of the inheriting class, which will be run with its own
query plan.
*/
virtual QueryOp *clone() const = 0;
bool complete() const { return complete_; }
bool error() const { return error_; }
string exceptionMessage() const { return exceptionMessage_; }
const QueryPlan &qp() const { return *qp_; }
// To be called by QueryPlanSet::Runner only.
void setQueryPlan( const QueryPlan *qp ) { qp_ = qp; }
void setExceptionMessage( const string &exceptionMessage ) {
error_ = true;
exceptionMessage_ = exceptionMessage;
}
protected:
void setComplete() { complete_ = true; }
private:
bool complete_;
string exceptionMessage_;
const QueryPlan *qp_;
bool error_;
};
// 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(); }
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;
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 );
}
void init();
void addHint( IndexDetails &id );
struct Runner {
Runner( QueryPlanSet &plans, QueryOp &op );
shared_ptr< QueryOp > run();
QueryOp &op_;
QueryPlanSet &plans_;
static void initOp( QueryOp &op );
static void nextOp( QueryOp &op );
};
const char *ns;
BSONObj query_;
FieldRangeSet fbs_;
PlanSet plans_;
bool mayRecordPlan_;
bool usingPrerecordedPlan_;
BSONObj hint_;
BSONObj order_;
long long oldNScanned_;
bool honorRecordedPlan_;
BSONObj min_;
BSONObj max_;
string _special;
};
// 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 );
inline bool isSimpleIdQuery( const BSONObj& query ){
return
strcmp( query.firstElement().fieldName() , "_id" ) == 0 &&
query.nFields() == 1 &&
query.firstElement().isSimpleType();
}
} // namespace mongo
|