Permalink
Browse files

SERVER-4665 backport 'ConstraintPresent' constraint type and exclusio…

…n of unhelpful recorded plans
  • Loading branch information...
1 parent 86e26ee commit 0b38e1009b7e43b84fd791cfc58bf83fb3c6d0eb @astaple astaple committed Jan 17, 2012
Showing with 51 additions and 7 deletions.
  1. +1 −1 db/queryoptimizer.cpp
  2. +2 −1 db/querypattern.h
  3. +2 −0 db/queryutil.cpp
  4. +18 −5 dbtests/queryutiltests.cpp
  5. +28 −0 jstests/queryoptimizer6.js
View
2 db/queryoptimizer.cpp
@@ -482,7 +482,7 @@ namespace mongo {
}
massert( 10368 , "Unable to locate previously recorded index", p.get() );
- if ( !( _bestGuessOnly && p->scanAndOrderRequired() ) ) {
+ if ( !p->unhelpful() && !( _bestGuessOnly && p->scanAndOrderRequired() ) ) {
_usingPrerecordedPlan = true;
_mayRecordPlan = false;
_plans.push_back( p );
View
3 db/querypattern.h
@@ -36,7 +36,8 @@ namespace mongo {
Equality,
LowerBound,
UpperBound,
- UpperAndLowerBound
+ UpperAndLowerBound,
+ ConstraintPresent
};
bool operator<( const QueryPattern &other ) const;
/** for testing only */
View
2 db/queryutil.cpp
@@ -1007,6 +1007,8 @@ namespace mongo {
qp._fieldTypes[ i->first ] = QueryPattern::UpperBound;
else if ( lower )
qp._fieldTypes[ i->first ] = QueryPattern::LowerBound;
+ else
+ qp._fieldTypes[ i->first ] = QueryPattern::ConstraintPresent;
}
}
qp.setSort( sort );
View
23 dbtests/queryutiltests.cpp
@@ -238,7 +238,14 @@ namespace QueryUtilTests {
}
};
- class QueryPatternTest {
+ class QueryPatternBase {
+ protected:
+ static QueryPattern p( const BSONObj &query, const BSONObj &sort = BSONObj() ) {
+ return FieldRangeSet( "", query, true ).pattern( sort );
+ }
+ };
+
+ class QueryPatternTest : public QueryPatternBase {
public:
void run() {
ASSERT( p( BSON( "a" << 1 ) ) == p( BSON( "a" << 1 ) ) );
@@ -258,12 +265,17 @@ namespace QueryUtilTests {
ASSERT( p( BSON( "a" << 1 ), BSON( "b" << 1 << "c" << 1 ) ) != p( BSON( "a" << 4 ), BSON( "b" << 1 ) ) );
ASSERT( p( BSON( "a" << 1 ), BSON( "b" << 1 ) ) != p( BSON( "a" << 4 ), BSON( "b" << 1 << "c" << 1 ) ) );
}
- private:
- static QueryPattern p( const BSONObj &query, const BSONObj &sort = BSONObj() ) {
- return FieldRangeSet( "", query, true ).pattern( sort );
+ };
+
+ class QueryPatternNeConstraint : public QueryPatternBase {
+ public:
+ void run() {
+ ASSERT( p( BSON( "a" << NE << 5 ) ) != p( BSON( "a" << GT << 1 ) ) );
+ ASSERT( p( BSON( "a" << NE << 5 ) ) != p( BSONObj() ) );
+ ASSERT( p( BSON( "a" << NE << 5 ) ) == p( BSON( "a" << NE << "a" ) ) );
}
};
-
+
class NoWhere {
public:
void run() {
@@ -902,6 +914,7 @@ namespace QueryUtilTests {
add< FieldRangeTests::Equality >();
add< FieldRangeTests::SimplifiedQuery >();
add< FieldRangeTests::QueryPatternTest >();
+ add< FieldRangeTests::QueryPatternNeConstraint >();
add< FieldRangeTests::NoWhere >();
add< FieldRangeTests::Numeric >();
add< FieldRangeTests::InLowerBound >();
View
28 jstests/queryoptimizer6.js
@@ -0,0 +1,28 @@
+// Test that $ne constraints are accounted for in QueryPattern. SERVER-4665
+
+t = db.jstests_queryoptimizer6;
+
+function reset() {
+ t.drop();
+ t.save( {a:1} );
+ t.ensureIndex( {b:1}, {sparse:true} );
+}
+
+reset();
+// The sparse index will be used, and recorded for this query pattern.
+assert.eq( 0, t.find( {a:1,b:{$ne:1}} ).itcount() );
+// The query pattern should be different, and the sparse index should not be used.
+assert.eq( 1, t.find( {a:1} ).itcount() );
+
+reset();
+// The sparse index will be used, and (for better or worse) recorded for this query pattern.
+assert.eq( 0, t.find( {a:1} ).min({b:1}).itcount() );
+// The sparse index should not be used, even though the query patterns match.
+assert.eq( 1, t.find( {a:1} ).itcount() );
+
+reset();
+t.ensureIndex( {a:1,b:1} );
+// The sparse index will be used, and (for better or worse) recorded for this query pattern.
+assert.eq( 0, t.find( {a:1,b:null} ).min({b:1}).itcount() );
+// Descriptive test - the recorded {b:1} index is used, because it is not useless.
+assert.eq( 0, t.find( {a:1,b:null} ).itcount() );

0 comments on commit 0b38e10

Please sign in to comment.