diff options
author | David Storch <david.storch@10gen.com> | 2014-08-27 15:36:08 -0400 |
---|---|---|
committer | David Storch <david.storch@10gen.com> | 2014-09-03 09:46:33 -0400 |
commit | 391b1121e36fd85d7e85c4442dccf8367e6da770 (patch) | |
tree | 0cf17a810a3c242b2c2a6363f9f18589fedc2fb6 /jstests/core | |
parent | 6bf17f12e3fde9bee14d2bb9c90001080546f867 (diff) | |
download | mongo-391b1121e36fd85d7e85c4442dccf8367e6da770.tar.gz |
SERVER-14742 delete old explain and turn on explain 2.0
Diffstat (limited to 'jstests/core')
102 files changed, 714 insertions, 1501 deletions
diff --git a/jstests/core/and.js b/jstests/core/and.js index 4d8c2cd7d49..f05c289966f 100644 --- a/jstests/core/and.js +++ b/jstests/core/and.js @@ -13,7 +13,7 @@ function check() { assert.throws( function() { t.find( {$and:[]} ).toArray() } ); // $and elements must be objects assert.throws( function() { t.find( {$and:[4]} ).toArray() } ); - + // Check equality matching assert.eq( 1, t.count( {$and:[{a:1}]} ) ); assert.eq( 1, t.count( {$and:[{a:1},{a:2}]} ) ); @@ -21,13 +21,13 @@ function check() { assert.eq( 0, t.count( {$and:[{a:1},{a:2},{a:3}]} ) ); assert.eq( 1, t.count( {$and:[{a:'foo'}]} ) ); assert.eq( 0, t.count( {$and:[{a:'foo'},{a:'g'}]} ) ); - + // Check $and with other fields assert.eq( 1, t.count( {a:2,$and:[{a:1}]} ) ); assert.eq( 0, t.count( {a:0,$and:[{a:1}]} ) ); assert.eq( 0, t.count( {a:2,$and:[{a:0}]} ) ); assert.eq( 1, t.count( {a:1,$and:[{a:1}]} ) ); - + // Check recursive $and assert.eq( 1, t.count( {a:2,$and:[{$and:[{a:1}]}]} ) ); assert.eq( 0, t.count( {a:0,$and:[{$and:[{a:1}]}]} ) ); @@ -38,10 +38,10 @@ function check() { assert.eq( 0, t.count( {$and:[{a:0},{$and:[{a:1}]}]} ) ); assert.eq( 0, t.count( {$and:[{a:2},{$and:[{a:0}]}]} ) ); assert.eq( 1, t.count( {$and:[{a:1},{$and:[{a:1}]}]} ) ); - + // Some of these cases were more important with an alternative $and syntax // that was rejected, but they're still valid checks. - + // Check simple regex assert.eq( 1, t.count( {$and:[{a:/foo/}]} ) ); // Check multiple regexes @@ -51,17 +51,15 @@ function check() { // Check regex flags assert.eq( 0, t.count( {$and:[{a:/^F/},{a:'foo'}]} ) ); assert.eq( 1, t.count( {$and:[{a:/^F/i},{a:'foo'}]} ) ); - - - + // Check operator assert.eq( 1, t.count( {$and:[{a:{$gt:0}}]} ) ); - + // Check where assert.eq( 1, t.count( {a:'foo',$where:'this.a=="foo"'} ) ); assert.eq( 1, t.count( {$and:[{a:'foo'}],$where:'this.a=="foo"'} ) ); assert.eq( 1, t.count( {$and:[{a:'foo'}],$where:'this.a=="foo"'} ) ); - + // Nested where ok assert.eq( 1, t.count({$and:[{$where:'this.a=="foo"'}]}) ); assert.eq( 1, t.count({$and:[{a:'foo'},{$where:'this.a=="foo"'}]}) ); @@ -71,15 +69,6 @@ function check() { check(); t.ensureIndex( {a:1} ); check(); -var e = t.find( {$and:[{a:1}]} ).explain(); -assert.eq( 'BtreeCursor a_1', e.cursor ); -assert.eq( [[1,1]], e.indexBounds.a ); - -function checkBounds( query ) { - var e = t.find( query ).explain(true); - printjson(e); - assert.eq( 1, e.n ); -} -checkBounds( {a:1,$and:[{a:2}]} ); -checkBounds( {$and:[{a:1},{a:2}]} ); +assert.eq( 1, t.find({a:1,$and:[{a:2}]}).itcount() ); +assert.eq( 1, t.find({$and:[{a:1},{a:2}]}).itcount() ); diff --git a/jstests/core/and3.js b/jstests/core/and3.js index 036c63c02f0..3f223265522 100644 --- a/jstests/core/and3.js +++ b/jstests/core/and3.js @@ -8,10 +8,10 @@ t.save( {a:'foo'} ); t.ensureIndex( {a:1} ); -function checkScanMatch( query, nscannedObjects, n ) { +function checkScanMatch( query, docsExamined, n ) { var e = t.find( query ).hint( {a:1} ).explain(); - assert.eq( nscannedObjects, e.nscannedObjects ); - assert.eq( n, e.n ); + assert.eq( docsExamined, e.executionStats.totalDocsExamined ); + assert.eq( n, e.executionStats.nReturned ); } checkScanMatch( {a:/o/}, 1, 1 ); @@ -51,17 +51,5 @@ checkScanMatch( {$and:[{a:1},{$where:'this.a==1'}]}, 1, 1 ); checkScanMatch( {$and:[{a:1,$where:'this.a==1'}]}, 1, 1 ); checkScanMatch( {a:1,$and:[{a:1},{a:1,$where:'this.a==1'}]}, 1, 1 ); -function checkImpossibleMatch( query ) { - var e = t.find( query ).explain(); - assert.eq( 0, e.n ); - // The explain output should include the indexBounds field. - // The presence of the indexBounds field indicates that the - // query can make use of an index. - assert('indexBounds' in e, 'index bounds are missing'); -} - -// With a single key index, all bounds are utilized. -assert.eq( [[1,1]], t.find( {$and:[{a:1}]} ).explain().indexBounds.a ); -assert.eq( [[1,1]], t.find( {a:1,$and:[{a:1}]} ).explain().indexBounds.a ); -checkImpossibleMatch( {a:1,$and:[{a:2}]} ); -checkImpossibleMatch( {$and:[{a:1},{a:2}]} ); +assert.eq( 0, t.find({a:1,$and:[{a:2}]}).itcount() ); +assert.eq( 0, t.find({$and:[{a:1},{a:2}]}).itcount() ); diff --git a/jstests/core/arrayfind1.js b/jstests/core/arrayfind1.js index 539fa6193a1..a731dd6bdf9 100644 --- a/jstests/core/arrayfind1.js +++ b/jstests/core/arrayfind1.js @@ -25,16 +25,9 @@ assert.eq( 1 , t.find( { a : { $elemMatch : { x : 2 } } } ).count() , "B1" ); assert.eq( 2 , t.find( { a : { $elemMatch : { x : { $gt : 2 } } } } ).count() , "B2" ); t.ensureIndex( { "a.x" : 1 } ); -assert( t.find( { "a" : { $elemMatch : { x : 1 } } } ).explain().cursor.indexOf( "BtreeC" ) == 0 , "C1" ); - assert.eq( 1 , t.find( { a : { $elemMatch : { x : 2 } } } ).count() , "D1" ); - -t.find( { "a.x" : 1 } ).count(); -t.find( { "a.x" : { $gt : 1 } } ).count(); - -res = t.find( { "a" : { $elemMatch : { x : { $gt : 2 } } } } ).explain() -assert( res.cursor.indexOf( "BtreeC" ) == 0 , "D2" ); +assert.eq( 3, t.find( { "a.x" : 1 } ).count() , "D2.1" ); +assert.eq( 3, t.find( { "a.x" : { $gt : 1 } } ).count() , "D2.2" ); assert.eq( 2 , t.find( { a : { $elemMatch : { x : { $gt : 2 } } } } ).count() , "D3" ); assert.eq( 2 , t.find( { a : { $ne:2, $elemMatch : { x : { $gt : 2 } } } } ).count() , "E1" ); -assert( t.find( { a : { $ne:2, $elemMatch : { x : { $gt : 2 } } } } ).explain().cursor.indexOf( "BtreeC" ) == 0 , "E2" ); diff --git a/jstests/core/arrayfind2.js b/jstests/core/arrayfind2.js index c6a78042c3d..ca6b57c518b 100644 --- a/jstests/core/arrayfind2.js +++ b/jstests/core/arrayfind2.js @@ -21,9 +21,3 @@ t.save( { a : [ { x : 3 } , { x : 6 } ] } ) go( "no index" ); t.ensureIndex( { a : 1 } ); go( "index(a)" ); - -t.ensureIndex( { "a.x": 1 } ); - -assert.eq( {"a.x":[[3,3]]}, t.find( { a : { $all : [ { $elemMatch : { x : 3 } } ] } } ).explain().indexBounds ); -// only first $elemMatch used to find bounds -assert.eq( {"a.x":[[3,3]]}, t.find( { a : { $all : [ { $elemMatch : { x : 3 } }, { $elemMatch : { y : 5 } } ] } } ).explain().indexBounds ); diff --git a/jstests/core/arrayfind6.js b/jstests/core/arrayfind6.js index f4531cea96a..9b54d5b2c07 100644 --- a/jstests/core/arrayfind6.js +++ b/jstests/core/arrayfind6.js @@ -19,8 +19,3 @@ function checkElemMatchMatches() { checkElemMatchMatches(); t.ensureIndex( { 'a.b':1 } ); checkElemMatchMatches(); - -// We currently never use an index for negations of -// ELEM_MATCH_OBJECT expressions. -var explain = t.find( { a:{ $not:{ $elemMatch:{ b:{ $ne:2 }, c:3 } } } } ).explain(); -assert.eq( "BasicCursor", explain.cursor ); diff --git a/jstests/core/arrayfind8.js b/jstests/core/arrayfind8.js index 07d44ace26e..7845bf38f72 100644 --- a/jstests/core/arrayfind8.js +++ b/jstests/core/arrayfind8.js @@ -20,12 +20,6 @@ function setIndexKey( key ) { setIndexKey( 'a' ); -function indexBounds( query ) { - debug( query ); - debug( t.find( query ).hint( indexSpec ).explain() ); - return t.find( query ).hint( indexSpec ).explain().indexBounds[ indexKey ]; -} - /** Check that the query results match the documents in the 'expected' array. */ function assertResults( expected, query, context ) { debug( query ); diff --git a/jstests/core/batch_size.js b/jstests/core/batch_size.js index 5af59ab5391..645ee0031ab 100644 --- a/jstests/core/batch_size.js +++ b/jstests/core/batch_size.js @@ -63,16 +63,18 @@ assert.eq(15, t.find({a: {$gte: 85}}).sort({b: 1}).hint({b: 1}).batchSize(2).itc assert.eq(6, t.find({a: {$gte: 85}}).sort({b: 1}).hint({b: 1}).limit(6).itcount(), 'P'); // With explain. -assert.eq(15, t.find({a: {$gte: 85}}).sort({b: 1}).batchSize(2).explain().n, 'Q'); -assert.eq(6, t.find({a: {$gte: 85}}).sort({b: 1}).limit(6).explain().n, 'R'); +var explain = t.find({a: {$gte: 85}}).sort({b: 1}).batchSize(2).explain(); +assert.eq(15, explain.executionStats.nReturned, 'Q'); +explain = t.find({a: {$gte: 85}}).sort({b: 1}).limit(6).explain(); +assert.eq(6, explain.executionStats.nReturned, 'R'); // Double check that we're not scanning more stuff than we have to. // In order to get the sort using index 'a', we should need to scan // about 50 keys and 50 documents. var explain = t.find({a: {$gte: 50}}).sort({b: 1}).hint({a: 1}).limit(6).explain(); -assert.lte(explain.nscanned, 60, 'S'); -assert.lte(explain.nscannedObjects, 60, 'T'); -assert.eq(explain.n, 6, 'U'); +assert.lte(explain.executionStats.totalKeysExamined, 60, 'S'); +assert.lte(explain.executionStats.totalDocsExamined, 60, 'T'); +assert.eq(explain.executionStats.nReturned, 6, 'U'); // ------- diff --git a/jstests/core/capped_empty.js b/jstests/core/capped_empty.js index 5b0fb6b8f8e..02c6bef4e45 100644 --- a/jstests/core/capped_empty.js +++ b/jstests/core/capped_empty.js @@ -10,7 +10,6 @@ t.insert( { x : 3 } ); t.ensureIndex( { x : 1 } ); assert.eq( 3 , t.count() ); -assert.eq( 1 , t.find( { x : 2 } ).explain().nscanned ); t.runCommand( "emptycapped" ); @@ -21,4 +20,3 @@ t.insert( { x : 2 } ); t.insert( { x : 3 } ); assert.eq( 3 , t.count() ); -assert.eq( 1 , t.find( { x : 2 } ).explain().nscanned ); diff --git a/jstests/core/coveredIndex1.js b/jstests/core/coveredIndex1.js index ce11f89ceed..54ef179f2b1 100644 --- a/jstests/core/coveredIndex1.js +++ b/jstests/core/coveredIndex1.js @@ -2,6 +2,9 @@ t = db["jstests_coveredIndex1"]; t.drop(); +// Include helpers for analyzing explain output. +load("jstests/libs/analyze_plan.js"); + t.save({fn: "john", ln: "doe"}) t.save({fn: "jack", ln: "doe"}) t.save({fn: "john", ln: "smith"}) @@ -13,52 +16,73 @@ assert.eq( t.count(), 6, "Not right length" ); // use simple index t.ensureIndex({ln: 1}); -assert.eq( t.find({ln: "doe"}).explain().indexOnly, false, "Find using covered index but all fields are returned"); -assert.eq( t.find({ln: "doe"}, {ln: 1}).explain().indexOnly, false, "Find using covered index but _id is returned"); -assert.eq( t.find({ln: "doe"}, {ln: 1, _id: 0}).explain().indexOnly, true, "Find is not using covered index"); +assert( !isIndexOnly(t.find({ln: "doe"}).explain().queryPlanner.winningPlan), + "Find using covered index but all fields are returned"); +assert( !isIndexOnly(t.find({ln: "doe"}, {ln: 1}).explain().queryPlanner.winningPlan), + "Find using covered index but _id is returned"); +assert( isIndexOnly(t.find({ln: "doe"}, {ln: 1, _id: 0}).explain().queryPlanner.winningPlan), + "Find is not using covered index"); // this time, without a query spec // SERVER-2109 //assert.eq( t.find({}, {ln: 1, _id: 0}).explain().indexOnly, true, "Find is not using covered index"); -assert.eq( t.find({}, {ln: 1, _id: 0}).hint({ln: 1}).explain().indexOnly, true, "Find is not using covered index"); +assert( isIndexOnly(t.find({}, {ln: 1, _id: 0}).hint({ln: 1}).explain().queryPlanner.winningPlan), + "Find is not using covered index"); // use compound index t.dropIndex({ln: 1}) t.ensureIndex({ln: 1, fn: 1}); // return 1 field -assert.eq( t.find({ln: "doe"}, {ln: 1, _id: 0}).explain().indexOnly, true, "Find is not using covered index"); +var plan = t.find({ln: "doe"}, {ln: 1, _id: 0}).explain(); +assert( isIndexOnly(plan.queryPlanner.winningPlan), "Find is not using covered index"); // return both fields, multiple docs returned -assert.eq( t.find({ln: "doe"}, {ln: 1, fn: 1, _id: 0}).explain().indexOnly, true, "Find is not using covered index"); +var plan = t.find({ln: "doe"}, {ln: 1, fn: 1, _id: 0}).explain(); +assert( isIndexOnly(plan.queryPlanner.winningPlan), "Find is not using covered index"); // match 1 record using both fields -assert.eq( t.find({ln: "doe", fn: "john"}, {ln: 1, fn: 1, _id: 0}).explain().indexOnly, true, "Find is not using covered index"); +var plan = t.find({ln: "doe", fn: "john"}, {ln: 1, fn: 1, _id: 0}).explain(); +assert( isIndexOnly(plan.queryPlanner.winningPlan), "Find is not using covered index"); // change ordering -assert.eq( t.find({fn: "john", ln: "doe"}, {fn: 1, ln: 1, _id: 0}).explain().indexOnly, true, "Find is not using covered index"); +var plan = t.find({fn: "john", ln: "doe"}, {fn: 1, ln: 1, _id: 0}).explain(); +assert( isIndexOnly(plan.queryPlanner.winningPlan), "Find is not using covered index"); // ask from 2nd index key -assert.eq( t.find({fn: "john"}, {fn: 1, _id: 0}).explain().indexOnly, false, "Find is using covered index, but doesnt have 1st key"); +var plan = t.find({fn: "john"}, {fn: 1, _id: 0}).explain(); +assert( !isIndexOnly(plan.queryPlanner.winningPlan), + "Find is using covered index, but doesnt have 1st key"); // repeat above but with _id field t.dropIndex({ln: 1, fn: 1}) t.ensureIndex({_id: 1, ln: 1}); // return 1 field -assert.eq( t.find({_id: 123, ln: "doe"}, {_id: 1}).explain().indexOnly, true, "Find is not using covered index"); +var plan = t.find({_id: 123, ln: "doe"}, {_id: 1}).explain(); +assert( isIndexOnly(plan.queryPlanner.winningPlan), "Find is not using covered index"); // match 1 record using both fields -assert.eq( t.find({_id: 123, ln: "doe"}, {ln: 1}).explain().indexOnly, true, "Find is not using covered index"); +var plan = t.find({_id: 123, ln: "doe"}, {ln: 1}).explain(); +assert( isIndexOnly(plan.queryPlanner.winningPlan), "Find is not using covered index"); // change ordering -assert.eq( t.find({ln: "doe", _id: 123}, {ln: 1, _id: 1}).explain().indexOnly, true, "Find is not using covered index"); +var plan = t.find({ln: "doe", _id: 123}, {ln: 1, _id: 1}).explain(); +assert( isIndexOnly(plan.queryPlanner.winningPlan), "Find is not using covered index"); // ask from 2nd index key -assert.eq( t.find({ln: "doe"}, {ln: 1}).explain().indexOnly, false, "Find is using covered index, but doesnt have 1st key"); +var plan = t.find({ln: "doe"}, {ln: 1}).explain(); +assert( !isIndexOnly(plan.queryPlanner.winningPlan), + "Find is using covered index, but doesnt have 1st key"); // repeat above but with embedded obj t.dropIndex({_id: 1, ln: 1}) t.ensureIndex({obj: 1}); -assert.eq( t.find({"obj.a": 1}, {obj: 1}).explain().indexOnly, false, "Shouldnt use index when introspecting object"); -assert.eq( t.find({obj: {a: 1, b: "blah"}}).explain().indexOnly, false, "Index doesnt have all fields to cover"); -assert.eq( t.find({obj: {a: 1, b: "blah"}}, {obj: 1, _id: 0}).explain().indexOnly, true, "Find is not using covered index"); +var plan = t.find({"obj.a": 1}, {obj: 1}).explain(); +assert( !isIndexOnly(plan.queryPlanner.winningPlan), + "Shouldnt use index when introspecting object"); +var plan = t.find({obj: {a: 1, b: "blah"}}).explain(); +assert( !isIndexOnly(plan.queryPlanner.winningPlan), "Index doesnt have all fields to cover"); +var plan = t.find({obj: {a: 1, b: "blah"}}, {obj: 1, _id: 0}).explain(); +assert( isIndexOnly(plan.queryPlanner.winningPlan), "Find is not using covered index"); // repeat above but with index on sub obj field t.dropIndex({obj: 1}); t.ensureIndex({"obj.a": 1, "obj.b": 1}) -assert.eq( t.find({"obj.a": 1}, {obj: 1}).explain().indexOnly, false, "Shouldnt use index when introspecting object"); +var plan = t.find({"obj.a": 1}, {obj: 1}).explain() +assert( !isIndexOnly(plan.queryPlanner.winningPlan), + "Shouldnt use index when introspecting object"); assert(t.validate().valid); diff --git a/jstests/core/coveredIndex2.js b/jstests/core/coveredIndex2.js index 56a23f43211..6abb280e422 100644 --- a/jstests/core/coveredIndex2.js +++ b/jstests/core/coveredIndex2.js @@ -1,6 +1,9 @@ t = db["jstests_coveredIndex2"]; t.drop(); +// Include helpers for analyzing explain output. +load("jstests/libs/analyze_plan.js"); + t.save({a: 1}) t.save({a: 2}) assert.eq( t.findOne({a: 1}).a, 1, "Cannot find right record" ); @@ -8,11 +11,18 @@ assert.eq( t.count(), 2, "Not right length" ); // use simple index t.ensureIndex({a: 1}); -assert.eq( t.find({a:1}).explain().indexOnly, false, "Find using covered index but all fields are returned"); -assert.eq( t.find({a:1}, {a: 1}).explain().indexOnly, false, "Find using covered index but _id is returned"); -assert.eq( t.find({a:1}, {a: 1, _id: 0}).explain().indexOnly, true, "Find is not using covered index"); +var plan = t.find({a:1}).explain(); +assert( !isIndexOnly(plan.queryPlanner.winningPlan), + "Find using covered index but all fields are returned"); +var plan = t.find({a:1}, {a: 1}).explain(); +assert( !isIndexOnly(plan.queryPlanner.winningPlan), + "Find using covered index but _id is returned"); +var plan = t.find({a:1}, {a: 1, _id: 0}).explain(); +assert( isIndexOnly(plan.queryPlanner.winningPlan), + "Find is not using covered index"); // add multikey t.save({a:[3,4]}) -assert.eq( t.find({a:1}, {a: 1, _id: 0}).explain().indexOnly, false, "Find is using covered index even after multikey insert"); - +var plan = t.find({a:1}, {a: 1, _id: 0}).explain(); +assert( !isIndexOnly(plan.queryPlanner.winningPlan), + "Find is using covered index even after multikey insert"); diff --git a/jstests/core/coveredIndex5.js b/jstests/core/coveredIndex5.js deleted file mode 100644 index ee383cd93e2..00000000000 --- a/jstests/core/coveredIndex5.js +++ /dev/null @@ -1,70 +0,0 @@ -// Test use of covered indexes when there are multiple candidate indexes. - -t = db.jstests_coveredIndex5; -t.drop(); - -t.ensureIndex( { a:1, b:1 } ); -t.ensureIndex( { a:1, c:1 } ); - -function checkFields( query, projection ) { - t.ensureIndex( { z:1 } ); // clear query patterns - t.dropIndex( { z:1 } ); - - results = t.find( query, projection ).toArray(); - - expectedFields = []; - for ( k in projection ) { - if ( k != '_id' ) { - expectedFields.push( k ); - } - } - - vals = []; - for ( i in results ) { - r = results[ i ]; - printjson(r); - assert.eq( 0, r.a ); - assert.eq( expectedFields, Object.keySet( r ) ); - for ( k in projection ) { - if ( k != '_id' && k != 'a' ) { - vals.push( r[ k ] ); - } - } - } - - if ( vals.length != 0 ) { - vals.sort(); - assert.eq( [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ], vals ); - } -} - -function checkCursorCovered( cursor, covered, count, query, projection ) { - checkFields( query, projection ); - explain = t.find( query, projection ).explain( true ); - if (covered) { - assert.eq( cursor, explain.cursor ); - } - assert.eq( covered, explain.indexOnly ); - assert.eq( count, explain.n ); -} - -for( i = 0; i < 10; ++i ) { - t.save( { a:0, b:i, c:9-i } ); -} - -checkCursorCovered( 'BtreeCursor a_1_b_1', true, 10, { a:0 }, { _id:0, a:1 } ); - -checkCursorCovered( 'BtreeCursor a_1_b_1', false, 10, { a:0, d:null }, { _id:0, a:1 } ); -checkCursorCovered( 'BtreeCursor a_1_b_1', false, 10, { a:0, d:null }, { _id:0, a:1, b:1 } ); - -// Covered index on a,c not preferentially selected. -checkCursorCovered( 'BtreeCursor a_1_b_1', false, 10, { a:0, d:null }, { _id:0, a:1, c:1 } ); - -t.save( { a:0, c:[ 1, 2 ] } ); -t.save( { a:1 } ); -checkCursorCovered( 'BtreeCursor a_1_b_1', false, 11, { a:0, d:null }, { _id:0, a:1 } ); - -t.save( { a:0, b:[ 1, 2 ] } ); -t.save( { a:1 } ); -checkCursorCovered( 'BtreeCursor a_1_b_1', false, 12, { a:0, d:null }, { _id:0, a:1 } ); - diff --git a/jstests/core/covered_index_compound_1.js b/jstests/core/covered_index_compound_1.js index 7e529785d12..632a2330b44 100644 --- a/jstests/core/covered_index_compound_1.js +++ b/jstests/core/covered_index_compound_1.js @@ -1,5 +1,8 @@ // Compound index covered query tests +// Include helpers for analyzing explain output. +load("jstests/libs/analyze_plan.js"); + var coll = db.getCollection("covered_compound_1") coll.drop() for (i=0;i<100;i++) { @@ -9,37 +12,51 @@ coll.ensureIndex({a:1,b:-1,c:1}) // Test equality - all indexed fields queried and projected var plan = coll.find({a:10, b:"strvar_10", c:0}, {a:1, b:1, c:1, _id:0}).hint({a:1, b:-1, c:1}).explain() -assert.eq(true, plan.indexOnly, "compound.1.1 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "compound.1.1 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "compound.1.1 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "compound.1.1 - nscannedObjects should be 0 for covered query") // Test query on subset of fields queried and project all var plan = coll.find({a:26, b:"strvar_0"}, {a:1, b:1, c:1, _id:0}).hint({a:1, b:-1, c:1}).explain() -assert.eq(true, plan.indexOnly, "compound.1.2 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "compound.1.2 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "compound.1.2 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "compound.1.2 - nscannedObjects should be 0 for covered query") // Test query on all fields queried and project subset var plan = coll.find({a:38, b:"strvar_12", c: 8}, {b:1, c:1, _id:0}).hint({a:1, b:-1, c:1}).explain() -assert.eq(true, plan.indexOnly, "compound.1.3 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "compound.1.3 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "compound.1.3 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "compound.1.3 - nscannedObjects should be 0 for covered query") // Test no query var plan = coll.find({}, {b:1, c:1, _id:0}).hint({a:1, b:-1, c:1}).explain() -assert.eq(true, plan.indexOnly, "compound.1.4 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "compound.1.4 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "compound.1.4 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "compound.1.4 - nscannedObjects should be 0 for covered query") // Test range query var plan = coll.find({a:{$gt:25,$lt:43}}, {b:1, c:1, _id:0}).hint({a:1, b:-1, c:1}).explain() -assert.eq(true, plan.indexOnly, "compound.1.5 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "compound.1.5 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "compound.1.5 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "compound.1.5 - nscannedObjects should be 0 for covered query") // Test in query var plan = coll.find({a:38, b:"strvar_12", c:{$in:[5,8]}}, {b:1, c:1, _id:0}).hint({a:1, b:-1, c:1}).explain() -assert.eq(true, plan.indexOnly, "compound.1.6 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "compound.1.6 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "compound.1.6 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "compound.1.6 - nscannedObjects should be 0 for covered query") // Test no result var plan = coll.find({a:38, b:"strvar_12", c:55},{a:1, b:1, c:1, _id:0}).hint({a:1, b:-1, c:1}).explain() -assert.eq(true, plan.indexOnly, "compound.1.7 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "compound.1.7 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "compound.1.7 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "compound.1.7 - nscannedObjects should be 0 for covered query") print('all tests passed') diff --git a/jstests/core/covered_index_geo_1.js b/jstests/core/covered_index_geo_1.js deleted file mode 100644 index 1d647dfa94c..00000000000 --- a/jstests/core/covered_index_geo_1.js +++ /dev/null @@ -1,18 +0,0 @@ -var coll = db.getCollection("covered_geo_1") -coll.drop() - -coll.insert({_id : 1, loc : [ 5 , 5 ], type : "type1"}) -coll.insert({_id : 2, loc : [ 6 , 6 ], type : "type2"}) -coll.insert({_id : 3, loc : [ 7 , 7 ], type : "type3"}) - -coll.ensureIndex({loc : "2d", type : 1}); - -var plan = coll.find({loc : [ 6 , 6 ]}, {loc:1, type:1, _id:0}).hint({loc:"2d", type:1}).explain(); -assert.eq(false, plan.indexOnly, "geo.1.1 - indexOnly should be false on a non covered query") -assert.neq(0, plan.nscannedObjects, "geo.1.1 - nscannedObjects should not be 0 for a non covered query") - -var plan = coll.find({loc : [ 6 , 6 ]}, {type:1, _id:0}).hint({loc:"2d", type:1}).explain(); -assert.eq(false, plan.indexOnly, "geo.1.2 - indexOnly should be false on a non covered query") -assert.neq(0, plan.nscannedObjects, "geo.1.2 - nscannedObjects should not be 0 for a non covered query") - -print("all tests passed")
\ No newline at end of file diff --git a/jstests/core/covered_index_geo_2.js b/jstests/core/covered_index_geo_2.js deleted file mode 100644 index 52f610b7e64..00000000000 --- a/jstests/core/covered_index_geo_2.js +++ /dev/null @@ -1,22 +0,0 @@ -var coll = db.getCollection("covered_geo_2") -coll.drop() - -coll.insert({_id : 1, loc1 : [ 5 , 5 ], type1 : "type1", - loc2 : [ 5 , 5 ], type2 : 1}) -coll.insert({_id : 2, loc1 : [ 6 , 6 ], type1 : "type2", - loc2 : [ 5 , 5 ], type2 : 2}) -coll.insert({_id : 3, loc1 : [ 7 , 7 ], type1 : "type3", - loc2 : [ 5 , 5 ], type2 : 3}) - -coll.ensureIndex({loc1 : "2dsphere", type1 : 1}); -coll.ensureIndex({type2: 1, loc2 : "2dsphere"}); - -var plan = coll.find({loc1 : {$nearSphere: [ 6 , 6 ]}}, {loc1:1, type1:1, _id:0}).hint({loc1:"2dsphere", type1:1}).explain(); -assert.eq(false, plan.indexOnly, "geo.2.1 - indexOnly should be false on a non covered query") -assert.neq(0, plan.nscannedObjects, "geo.2.1 - nscannedObjects should not be 0 for a non covered query") - -var plan = coll.find({loc1 : {$nearSphere: [ 6 , 6 ]}}, {type1:1, _id:0}).hint({loc1:"2dsphere", type1:1}).explain(); -assert.eq(false, plan.indexOnly, "geo.2.2 - indexOnly should be false for a non covered query") -assert.neq(0, plan.nscannedObjects, "geo.2.2 - nscannedObjects should not be 0 for a non covered query") - -print("all tests passed") diff --git a/jstests/core/covered_index_negative_1.js b/jstests/core/covered_index_negative_1.js index ab03e7566f6..4b538b7c275 100644 --- a/jstests/core/covered_index_negative_1.js +++ b/jstests/core/covered_index_negative_1.js @@ -3,6 +3,9 @@ // covered index query. Hence we expect indexOnly=false and // nscannedObjects > 0 +// Include helpers for analyzing explain output. +load("jstests/libs/analyze_plan.js"); + var coll = db.getCollection("covered_negative_1") coll.drop() for (i=0;i<100;i++) { @@ -16,23 +19,31 @@ coll.ensureIndex({f:"hashed"}) // Test no projection var plan = coll.find({a:10, b:"strvar_10", c:0}).hint({a:1, b:-1, c:1}).explain() -assert.eq(false, plan.indexOnly, "negative.1.1 - indexOnly should be false on a non covered query") -assert.neq(0, plan.nscannedObjects, "negative.1.1 - nscannedObjects should not be 0 for a non covered query") +assert(!isIndexOnly(plan.queryPlanner.winningPlan), + "negative.1.1 - indexOnly should be false on a non covered query") +assert.neq(0, plan.executionStats.totalDocsExamined, + "negative.1.1 - docs examined should not be 0 for a non covered query") // Test projection and not excluding _id var plan = coll.find({a:10, b:"strvar_10", c:0},{a:1, b:1, c:1}).hint({a:1, b:-1, c:1}).explain() -assert.eq(false, plan.indexOnly, "negative.1.2 - indexOnly should be false on a non covered query") -assert.neq(0, plan.nscannedObjects, "negative.1.2 - nscannedObjects should not be 0 for a non covered query") +assert(!isIndexOnly(plan.queryPlanner.winningPlan), + "negative.1.2 - indexOnly should be false on a non covered query") +assert.neq(0, plan.executionStats.totalDocsExamined, + "negative.1.2 - docs examined should not be 0 for a non covered query") // Test projection of non-indexed field var plan = coll.find({d:100},{d:1, c:1, _id:0}).hint({d:1}).explain() -assert.eq(false, plan.indexOnly, "negative.1.3 - indexOnly should be false on a non covered query") -assert.neq(0, plan.nscannedObjects, "negative.1.3 - nscannedObjects should not be 0 for a non covered query") +assert(!isIndexOnly(plan.queryPlanner.winningPlan), + "negative.1.3 - indexOnly should be false on a non covered query") +assert.neq(0, plan.executionStats.totalDocsExamined, + "negative.1.3 - docs examined should not be 0 for a non covered query") // Test query and projection on a multi-key index var plan = coll.find({e:99},{e:1, _id:0}).hint({e:1}).explain() -assert.eq(false, plan.indexOnly, "negative.1.4 - indexOnly should be false on a non covered query") -assert.neq(0, plan.nscannedObjects, "negative.1.4 - nscannedObjects should not be 0 for a non covered query") +assert(!isIndexOnly(plan.queryPlanner.winningPlan), + "negative.1.4 - indexOnly should be false on a non covered query") +assert.neq(0, plan.executionStats.totalDocsExamined, + "negative.1.4 - docs examined should not be 0 for a non covered query") // Commenting out negative.1.5 and 1.6 pending fix in SERVER-8650 // // Test projection and $natural sort @@ -49,13 +60,16 @@ assert.neq(0, plan.nscannedObjects, "negative.1.4 - nscannedObjects should not b // Test query on non-indexed field var plan = coll.find({d:{$lt:1000}},{a:1, b:1, c:1, _id:0}).hint({a:1, b:-1, c:1}).explain() -//indexOnly should be false but is not due to bug https://jira.mongodb.org/browse/SERVER-8562 -// assert.eq(true, plan.indexOnly, "negative.1.7 - indexOnly should be false on a non covered query") -assert.neq(0, plan.nscannedObjects, "negative.1.7 - nscannedObjects should not be 0 for a non covered query") +assert(!isIndexOnly(plan.queryPlanner.winningPlan), + "negative.1.7 - indexOnly should be false on a non covered query") +assert.neq(0, plan.executionStats.totalDocsExamined, + "negative.1.7 - docs examined should not be 0 for a non covered query") // Test query on hashed indexed field var plan = coll.find({f:10},{f:1, _id:0}).hint({f:"hashed"}).explain() -assert.eq(false, plan.indexOnly, "negative.1.8 - indexOnly should be false on a non covered query") -assert.neq(0, plan.nscannedObjects, "negative.1.8 - nscannedObjects should not be 0 for a non covered query") +assert(!isIndexOnly(plan.queryPlanner.winningPlan), + "negative.1.8 - indexOnly should be false on a non covered query") +assert.neq(0, plan.executionStats.totalDocsExamined, + "negative.1.8 - nscannedObjects should not be 0 for a non covered query") print('all tests passed') diff --git a/jstests/core/covered_index_simple_1.js b/jstests/core/covered_index_simple_1.js index 44e3c00a9f8..146f0751f1c 100644 --- a/jstests/core/covered_index_simple_1.js +++ b/jstests/core/covered_index_simple_1.js @@ -1,5 +1,8 @@ // Simple covered index query test +// Include helpers for analyzing explain output. +load("jstests/libs/analyze_plan.js"); + var coll = db.getCollection("covered_simple_1") coll.drop() for (i=0;i<10;i++) { @@ -18,38 +21,51 @@ coll.ensureIndex({foo:1}) // Test equality with int value var plan = coll.find({foo:1}, {foo:1, _id:0}).hint({foo:1}).explain() -assert.eq(true, plan.indexOnly, "simple.1.1 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "simple.1.1 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.1.1 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.1.1 - docs examined should be 0 for covered query") // Test equality with string value var plan = coll.find({foo:"string"}, {foo:1, _id:0}).hint({foo:1}).explain() -assert.eq(true, plan.indexOnly, "simple.1.2 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "simple.1.2 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.1.2 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.1.2 - docs examined should be 0 for covered query") // Test equality with doc value var plan = coll.find({foo:{bar:1}}, {foo:1, _id:0}).hint({foo:1}).explain() -assert.eq(true, plan.indexOnly, "simple.1.3 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "simple.1.3 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.1.3 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.1.3 - docs examined should be 0 for covered query") // Test no query var plan = coll.find({}, {foo:1, _id:0}).hint({foo:1}).explain() -assert.eq(true, plan.indexOnly, "simple.1.4 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "simple.1.4 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.1.4 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.1.4 - docs examined should be 0 for covered query") // Test range query var plan = coll.find({foo:{$gt:2,$lt:6}}, {foo:1, _id:0}).hint({foo:1}).explain() -assert.eq(true, plan.indexOnly, "simple.1.5 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "simple.1.5 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.1.5 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.1.5 - docs examined should be 0 for covered query") // Test in query var plan = coll.find({foo:{$in:[5,8]}}, {foo:1, _id:0}).hint({foo:1}).explain() -assert.eq(true, plan.indexOnly, "simple.1.6 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "simple.1.6 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.1.6 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.1.6 - docs examined should be 0 for covered query") // Test no return var plan = coll.find({foo:"2"}, {foo:1, _id:0}).hint({foo:1}).explain() -assert.eq(true, plan.indexOnly, "simple.1.7 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "simple.1.7 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.1.7 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.1.7 - nscannedObjects should be 0 for covered query") print ('all tests pass') - diff --git a/jstests/core/covered_index_simple_2.js b/jstests/core/covered_index_simple_2.js index 313cca439d8..014f235b711 100644 --- a/jstests/core/covered_index_simple_2.js +++ b/jstests/core/covered_index_simple_2.js @@ -1,5 +1,8 @@ // Simple covered index query test with unique index +// Include helpers for analyzing explain output. +load("jstests/libs/analyze_plan.js"); + var coll = db.getCollection("covered_simple_2") coll.drop() for (i=0;i<10;i++) { @@ -12,32 +15,44 @@ coll.ensureIndex({foo:1},{unique:true}) // Test equality with int value var plan = coll.find({foo:1}, {foo:1, _id:0}).hint({foo:1}).explain() -assert.eq(true, plan.indexOnly, "simple.2.1 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "simple.2.1 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.2.1 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.2.1 - docs examined should be 0 for covered query") // Test equality with string value var plan = coll.find({foo:"string"}, {foo:1, _id:0}).hint({foo:1}).explain() -assert.eq(true, plan.indexOnly, "simple.2.2 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "simple.2.2 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.2.2 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.2.2 - docs examined should be 0 for covered query") // Test equality with int value on a dotted field var plan = coll.find({foo:{bar:1}}, {foo:1, _id:0}).hint({foo:1}).explain() -assert.eq(true, plan.indexOnly, "simple.2.3 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "simple.2.3 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.2.3 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.2.3 - docs examined should be 0 for covered query"); // Test no query var plan = coll.find({}, {foo:1, _id:0}).hint({foo:1}).explain() -assert.eq(true, plan.indexOnly, "simple.2.4 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "simple.2.4 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.2.4 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.2.4 - docs examined should be 0 for covered query"); // Test range query var plan = coll.find({foo:{$gt:2,$lt:6}}, {foo:1, _id:0}).hint({foo:1}).explain() -assert.eq(true, plan.indexOnly, "simple.2.5 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "simple.2.5 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.2.5 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.2.5 - docs examined should be 0 for covered query"); // Test in query var plan = coll.find({foo:{$in:[5,8]}}, {foo:1, _id:0}).hint({foo:1}).explain() -assert.eq(true, plan.indexOnly, "simple.2.6 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "simple.2.6 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.2.6 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.2.6 - docs examined should be 0 for covered query"); print ('all tests pass') diff --git a/jstests/core/covered_index_simple_3.js b/jstests/core/covered_index_simple_3.js index ffd80f73b5b..32f411798ec 100644 --- a/jstests/core/covered_index_simple_3.js +++ b/jstests/core/covered_index_simple_3.js @@ -1,5 +1,8 @@ // Simple covered index query test with a unique sparse index +// Include helpers for analyzing explain output. +load("jstests/libs/analyze_plan.js"); + var coll = db.getCollection("covered_simple_3"); coll.drop(); for (i=0;i<10;i++) { @@ -15,44 +18,60 @@ coll.ensureIndex({foo:1}, {sparse:true, unique:true}); // Test equality with int value var plan = coll.find({foo:1}, {foo:1, _id:0}).hint({foo:1}).explain(); -assert.eq(true, plan.indexOnly, "simple.3.1 - indexOnly should be true on covered query"); -assert.eq(0, plan.nscannedObjects, "simple.3.1 - nscannedObjects should be 0 for covered query"); +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.3.1 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.3.1 - docs examined should be 0 for covered query") // Test equality with string value var plan = coll.find({foo:"string"}, {foo:1, _id:0}).hint({foo:1}).explain(); -assert.eq(true, plan.indexOnly, "simple.3.2 - indexOnly should be true on covered query"); -assert.eq(0, plan.nscannedObjects, "simple.3.2 - nscannedObjects should be 0 for covered query"); +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.3.2 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.3.2 - docs examined should be 0 for covered query") // Test equality with int value on a dotted field var plan = coll.find({foo:{bar:1}}, {foo:1, _id:0}).hint({foo:1}).explain(); -assert.eq(true, plan.indexOnly, "simple.3.3 - indexOnly should be true on covered query"); -assert.eq(0, plan.nscannedObjects, "simple.3.3 - nscannedObjects should be 0 for covered query"); +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.3.3 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.3.3 - docs examined should be 0 for covered query") // Test no query var plan = coll.find({}, {foo:1, _id:0}).hint({foo:1}).explain(); -assert.eq(true, plan.indexOnly, "simple.3.4 - indexOnly should be true on covered query"); -assert.eq(0, plan.nscannedObjects, "simple.3.4 - nscannedObjects should be 0 for covered query"); +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.3.4 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.3.4 - docs examined should be 0 for covered query") // Test range query var plan = coll.find({foo:{$gt:2,$lt:6}}, {foo:1, _id:0}).hint({foo:1}).explain(); -assert.eq(true, plan.indexOnly, "simple.3.5 - indexOnly should be true on covered query"); -assert.eq(0, plan.nscannedObjects, "simple.3.5 - nscannedObjects should be 0 for covered query"); +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.3.5 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.3.5 - docs examined should be 0 for covered query") // Test in query var plan = coll.find({foo:{$in:[5,8]}}, {foo:1, _id:0}).hint({foo:1}).explain(); -assert.eq(true, plan.indexOnly, "simple.3.6 - indexOnly should be true on covered query"); -assert.eq(0, plan.nscannedObjects, "simple.3.6 - nscannedObjects should be 0 for covered query"); +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.3.6 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.3.6 - docs examined should be 0 for covered query") // Test $exists true var plan = coll.find({foo:{$exists:true}}, {foo:1, _id:0}).hint({foo:1}).explain(); -assert.eq(true, plan.indexOnly, "simple.3.7 - indexOnly should be true on covered query"); -assert.eq(0, plan.nscannedObjects, "simple.3.7 - nscannedObjects should be 0 for covered query"); +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.3.7 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.3.7 - docs examined should be 0 for covered query") // Check that $nin can be covered. coll.dropIndexes(); coll.ensureIndex({bar: 1}); var plan = coll.find({bar:{$nin:[5,8]}}, {bar:1, _id:0}).hint({bar:1}).explain() -assert.eq(true, plan.indexOnly, "simple.3.8 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "simple.3.8 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.3.8 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.3.8 - docs examined should be 0 for covered query") print ('all tests pass') diff --git a/jstests/core/covered_index_simple_id.js b/jstests/core/covered_index_simple_id.js index c7f6811a33c..8016854cb0a 100644 --- a/jstests/core/covered_index_simple_id.js +++ b/jstests/core/covered_index_simple_id.js @@ -1,5 +1,8 @@ // Simple covered index query test +// Include helpers for analyzing explain output. +load("jstests/libs/analyze_plan.js"); + var coll = db.getCollection("covered_simple_id") coll.drop() for (i=0;i<10;i++) { @@ -11,32 +14,44 @@ coll.insert({_id:null}) // Test equality with int value var plan = coll.find({_id:1}, {_id:1}).hint({_id:1}).explain() -assert.eq(true, plan.indexOnly, "simple.id.1 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "simple.id.1 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.id.1 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.id.1 - docs examined should be 0 for covered query") // Test equality with string value var plan = coll.find({_id:"string"}, {_id:1}).hint({_id:1}).explain() -assert.eq(true, plan.indexOnly, "simple.id.2 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "simple.id.2 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.id.2 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.id.2 - docs examined should be 0 for covered query") // Test equality with int value on a dotted field var plan = coll.find({_id:{bar:1}}, {_id:1}).hint({_id:1}).explain() -assert.eq(true, plan.indexOnly, "simple.id.3 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "simple.id.3 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.id.3 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.id.3 - docs examined should be 0 for covered query") // Test no query var plan = coll.find({}, {_id:1}).hint({_id:1}).explain() -assert.eq(true, plan.indexOnly, "simple.id.4 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "simple.id.4 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.id.4 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.id.4 - docs examined should be 0 for covered query") // Test range query var plan = coll.find({_id:{$gt:2,$lt:6}}, {_id:1}).hint({_id:1}).explain() -assert.eq(true, plan.indexOnly, "simple.id.5 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "simple.id.5 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.id.5 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.id.5 - docs examined should be 0 for covered query") // Test in query var plan = coll.find({_id:{$in:[5,8]}}, {_id:1}).hint({_id:1}).explain() -assert.eq(true, plan.indexOnly, "simple.id.6 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "simple.id.6 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "simple.id.6 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "simple.id.6 - docs examined should be 0 for covered query") print ('all tests pass') diff --git a/jstests/core/covered_index_sort_1.js b/jstests/core/covered_index_sort_1.js index adfcb5c6cb6..fd7d77d272e 100644 --- a/jstests/core/covered_index_sort_1.js +++ b/jstests/core/covered_index_sort_1.js @@ -1,5 +1,8 @@ // Simple covered index query test with sort +// Include helpers for analyzing explain output. +load("jstests/libs/analyze_plan.js"); + var coll = db.getCollection("covered_sort_1") coll.drop() for (i=0;i<10;i++) { @@ -18,17 +21,23 @@ coll.ensureIndex({foo:1}) // Test no query and sort ascending var plan = coll.find({}, {foo:1, _id:0}).sort({foo:1}).hint({foo:1}).explain() -assert.eq(true, plan.indexOnly, "sort.1.1 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "sort.1.1 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "sort.1.1 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "sort.1.1 - docs examined should be 0 for covered query") // Test no query and sort descending var plan = coll.find({}, {foo:1, _id:0}).sort({foo:-1}).hint({foo:1}).explain() -assert.eq(true, plan.indexOnly, "sort.1.2 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "sort.1.2 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "sort.1.2 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "sort.1.2 - docs examined should be 0 for covered query") // Test range query with sort var plan = coll.find({foo:{$gt:2}}, {foo:1, _id:0}).sort({foo:-1}).hint({foo:1}).explain() -assert.eq(true, plan.indexOnly, "sort.1.5 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "sort.1.5 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "sort.1.3 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "sort.1.3 - docs examined should be 0 for covered query") -print ('all tests pass')
\ No newline at end of file +print ('all tests pass') diff --git a/jstests/core/covered_index_sort_2.js b/jstests/core/covered_index_sort_2.js index e5dd48b47af..4315bdc448a 100644 --- a/jstests/core/covered_index_sort_2.js +++ b/jstests/core/covered_index_sort_2.js @@ -1,5 +1,8 @@ // Simple covered index query test with sort on _id +// Include helpers for analyzing explain output. +load("jstests/libs/analyze_plan.js"); + var coll = db.getCollection("covered_sort_2") coll.drop() for (i=0;i<10;i++) { @@ -11,7 +14,9 @@ coll.insert({_id:null}) // Test no query var plan = coll.find({}, {_id:1}).sort({_id:-1}).hint({_id:1}).explain() -assert.eq(true, plan.indexOnly, "sort.2.1 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "sort.2.1 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "sort.2.1 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "sort.2.1 - docs examined should be 0 for covered query") -print ('all tests pass')
\ No newline at end of file +print ('all tests pass') diff --git a/jstests/core/covered_index_sort_3.js b/jstests/core/covered_index_sort_3.js index 8f5986c4d76..6b5cae9def2 100644 --- a/jstests/core/covered_index_sort_3.js +++ b/jstests/core/covered_index_sort_3.js @@ -1,5 +1,8 @@ // Compound index covered query tests with sort +// Include helpers for analyzing explain output. +load("jstests/libs/analyze_plan.js"); + var coll = db.getCollection("covered_sort_3") coll.drop() for (i=0;i<100;i++) { @@ -10,7 +13,9 @@ coll.ensureIndex({a:1,b:-1,c:1}) // Test no query, sort on all fields in index order var plan = coll.find({}, {b:1, c:1, _id:0}).sort({a:1,b:-1,c:1}).hint({a:1, b:-1, c:1}).explain() -assert.eq(true, plan.indexOnly, "compound.1.1 - indexOnly should be true on covered query") -assert.eq(0, plan.nscannedObjects, "compound.1.1 - nscannedObjects should be 0 for covered query") +assert(isIndexOnly(plan.queryPlanner.winningPlan), + "sort.3.1 - indexOnly should be true on covered query") +assert.eq(0, plan.executionStats.totalDocsExamined, + "sort.3.1 - docs examined should be 0 for covered query") print ('all tests pass') diff --git a/jstests/core/cursor6.js b/jstests/core/cursor6.js index 9c50e9ecbb2..05af609e7ea 100644 --- a/jstests/core/cursor6.js +++ b/jstests/core/cursor6.js @@ -5,23 +5,6 @@ function eq( one, two ) { assert.eq( one.b, two.b ); } -function checkExplain( e, idx, reverse, nScanned ) { - if ( !reverse ) { - if ( idx ) { - assert.eq( "BtreeCursor a_1_b_-1", e.cursor ); - } else { - assert.eq( "BasicCursor", e.cursor ); - } - } else { - if ( idx ) { - assert.eq( "BtreeCursor a_1_b_-1 reverse", e.cursor ); - } else { - assert( false ); - } - } - assert.eq( nScanned, e.nscanned ); -} - function check( indexed ) { var hint; if ( indexed ) { @@ -29,51 +12,37 @@ function check( indexed ) { } else { hint = { $natural: 1 }; } - - e = r.find().sort( { a: 1, b: 1 } ).hint( hint ).explain(); - checkExplain( e, indexed, false, 4 ); + f = r.find().sort( { a: 1, b: 1 } ).hint( hint ); eq( z[ 0 ], f[ 0 ] ); eq( z[ 1 ], f[ 1 ] ); eq( z[ 2 ], f[ 2 ] ); eq( z[ 3 ], f[ 3 ] ); - e = r.find().sort( { a: 1, b: -1 } ).hint( hint ).explain(); - checkExplain( e, indexed, false, 4 ); f = r.find().sort( { a: 1, b: -1 } ).hint( hint ); eq( z[ 1 ], f[ 0 ] ); eq( z[ 0 ], f[ 1 ] ); eq( z[ 3 ], f[ 2 ] ); eq( z[ 2 ], f[ 3 ] ); - e = r.find().sort( { a: -1, b: 1 } ).hint( hint ).explain(); - checkExplain( e, indexed, true && indexed, 4 ); f = r.find().sort( { a: -1, b: 1 } ).hint( hint ); eq( z[ 2 ], f[ 0 ] ); eq( z[ 3 ], f[ 1 ] ); eq( z[ 0 ], f[ 2 ] ); eq( z[ 1 ], f[ 3 ] ); - e = r.find( { a: { $gte: 2 } } ).sort( { a: 1, b: -1 } ).hint( hint ).explain(); - checkExplain( e, indexed, false, indexed ? 2 : 4 ); f = r.find( { a: { $gte: 2 } } ).sort( { a: 1, b: -1 } ).hint( hint ); eq( z[ 3 ], f[ 0 ] ); eq( z[ 2 ], f[ 1 ] ); - e = r.find( { a : { $gte: 2 } } ).sort( { a: -1, b: 1 } ).hint( hint ).explain(); - checkExplain( e, indexed, true && indexed, indexed ? 2 : 4 ); f = r.find( { a: { $gte: 2 } } ).sort( { a: -1, b: 1 } ).hint( hint ); eq( z[ 2 ], f[ 0 ] ); eq( z[ 3 ], f[ 1 ] ); - e = r.find( { a : { $gte: 2 } } ).sort( { a: 1, b: 1 } ).hint( hint ).explain(); - checkExplain( e, indexed, false, indexed ? 2 : 4 ); f = r.find( { a: { $gte: 2 } } ).sort( { a: 1, b: 1 } ).hint( hint ); eq( z[ 2 ], f[ 0 ] ); eq( z[ 3 ], f[ 1 ] ); - e = r.find().sort( { a: -1, b: -1 } ).hint( hint ).explain(); - checkExplain( e, indexed, false, 4 ); f = r.find().sort( { a: -1, b: -1 } ).hint( hint ); eq( z[ 3 ], f[ 0 ] ); eq( z[ 2 ], f[ 1 ] ); @@ -97,6 +66,4 @@ r.ensureIndex( { a: 1, b: -1 } ); check( false ); check( true ); -assert.eq( "BasicCursor", r.find().sort( { a: 1, b: -1, z: 1 } ).hint( { $natural: -1 } ).explain().cursor ); - db.setProfilingLevel( 0 ); diff --git a/jstests/core/cursora.js b/jstests/core/cursora.js index 6710c1e9dc6..3e565c4835e 100644 --- a/jstests/core/cursora.js +++ b/jstests/core/cursora.js @@ -23,8 +23,11 @@ function run( n , atomic ){ var end = null; try { start = new Date() - ex = t.find(function () { num = 2; for (var x = 0; x < 1000; x++) num += 2; return num > 0; }).sort({ _id: -1 }).explain() - num = ex.n + num = t.find(function () { + num = 2; + for (var x = 0; x < 1000; x++) num += 2; + return num > 0; + }).sort({ _id: -1 }).itcount(); end = new Date() } catch (e) { @@ -32,7 +35,7 @@ function run( n , atomic ){ join(); throw e; } - + join() //print( "cursora.js num: " + num + " time:" + ( end.getTime() - start.getTime() ) ) diff --git a/jstests/core/distinct_speed1.js b/jstests/core/distinct_speed1.js index 4cae5b0ae06..2e21f5463b9 100644 --- a/jstests/core/distinct_speed1.js +++ b/jstests/core/distinct_speed1.js @@ -9,7 +9,7 @@ for ( var i=0; i<10000; i++ ){ assert.eq( 10 , t.distinct("x").length , "A1" ); function fast(){ - t.find().explain().millis; + t.find().explain().executionStats.executionTimeMillis; } function slow(){ diff --git a/jstests/core/exists6.js b/jstests/core/exists6.js index 2fa4ba85d49..79d4885283d 100644 --- a/jstests/core/exists6.js +++ b/jstests/core/exists6.js @@ -8,64 +8,10 @@ t.save( {} ); t.save( {b:1} ); t.save( {b:null} ); -//--------------------------------- - -function checkIndexUse( query, usesIndex, index, bounds ) { - var x = t.find( query ).explain() - if ( usesIndex ) { - assert.eq( x.cursor.indexOf(index), 0 , tojson(x) ); - if ( ! x.indexBounds ) x.indexBounds = {} - assert.eq( bounds, x.indexBounds.b , tojson(x) ); - } - else { - assert.eq( 'BasicCursor', x.cursor, tojson(x) ); - } -} - -function checkExists( query, usesIndex, bounds ) { - checkIndexUse( query, usesIndex, 'BtreeCursor b_1', bounds ); - // Whether we use an index or not, we will always scan all docs. - assert.eq( 3, t.find( query ).explain().nscanned ); - // 2 docs will match. - assert.eq( 2, t.find( query ).itcount() ); -} - -function checkMissing( query, usesIndex, bounds ) { - checkIndexUse( query, usesIndex, 'BtreeCursor b_1', bounds ); - // Nscanned changes based on index usage. - if ( usesIndex ) assert.eq( 2, t.find( query ).explain().nscanned ); - else assert.eq( 3, t.find( query ).explain().nscanned ); - // 1 doc is missing 'b'. - assert.eq( 1, t.find( query ).itcount() ); -} - -function checkExistsCompound( query, usesIndex, bounds ) { - checkIndexUse( query, usesIndex, 'BtreeCursor', bounds ); - if ( usesIndex ) assert.eq( 3, t.find( query ).explain().nscanned ); - else assert.eq( 3, t.find( query ).explain().nscanned ); - // 2 docs have a:1 and b:exists. - assert.eq( 2, t.find( query ).itcount() ); -} - -function checkMissingCompound( query, usesIndex, bounds ) { - checkIndexUse( query, usesIndex, 'BtreeCursor', bounds ); - // two possible indexes to use - // 1 doc should match - assert.eq( 1, t.find( query ).itcount() ); -} - -//--------------------------------- - -var allValues = [ [ { $minElement:1 }, { $maxElement:1 } ] ]; -var nullNull = [ [ null, null ] ]; - -// Basic cases -checkExists( {b:{$exists:true}}, true, allValues ); -// We change this to not -> not -> exists:true, and get allValue for bounds -// but we use a BasicCursor? -checkExists( {b:{$not:{$exists:false}}}, false, allValues ); -checkMissing( {b:{$exists:false}}, true, nullNull ); -checkMissing( {b:{$not:{$exists:true}}}, true, nullNull ); +assert.eq( 2, t.find({b:{$exists:true}}).itcount() ); +assert.eq( 2, t.find({b:{$not:{$exists:false}}}).itcount() ); +assert.eq( 1, t.find({b:{$exists:false}}).itcount() ); +assert.eq( 1, t.find({b:{$not:{$exists:true}}}).itcount() ); // Now check existence of second compound field. t.ensureIndex( {a:1,b:1} ); @@ -73,7 +19,7 @@ t.save( {a:1} ); t.save( {a:1,b:1} ); t.save( {a:1,b:null} ); -checkExistsCompound( {a:1,b:{$exists:true}}, true, allValues ); -checkExistsCompound( {a:1,b:{$not:{$exists:false}}}, true, allValues ); -checkMissingCompound( {a:1,b:{$exists:false}}, true, nullNull ); -checkMissingCompound( {a:1,b:{$not:{$exists:true}}}, true, nullNull ); +assert.eq( 2, t.find({a:1,b:{$exists:true}}).itcount() ); +assert.eq( 2, t.find({a:1,b:{$not:{$exists:false}}}).itcount() ); +assert.eq( 1, t.find({a:1,b:{$exists:false}}).itcount() ); +assert.eq( 1, t.find({a:1,b:{$not:{$exists:true}}}).itcount() ); diff --git a/jstests/core/exists9.js b/jstests/core/exists9.js index 66378d1b424..75b09018797 100644 --- a/jstests/core/exists9.js +++ b/jstests/core/exists9.js @@ -25,7 +25,6 @@ assert.eq( 1, t.count( {a:{$exists:false}} ) ); t.ensureIndex( {a:1} ); assert.eq( 1, t.find( {a:{$exists:true}} ).hint( {a:1} ).itcount() ); assert.eq( 1, t.find( {a:{$exists:false}} ).hint( {a:1} ).itcount() ); -assert.eq( 1, t.find( {a:{$exists:false}} ).hint( {a:1} ).explain().nscanned ); t.drop(); diff --git a/jstests/core/existsa.js b/jstests/core/existsa.js index 9ef7e9f374c..d1fecc2461e 100644 --- a/jstests/core/existsa.js +++ b/jstests/core/existsa.js @@ -13,18 +13,11 @@ function setIndex( _indexKeyField ) { indexKeySpec = {}; indexKeySpec[ indexKeyField ] = 1; t.ensureIndex( indexKeySpec, { sparse:true } ); - indexCursorName = 'BtreeCursor ' + indexKeyField + '_1'; } setIndex( 'a' ); -/** Validate the prefix of 'str'. */ -function assertPrefix( prefix, str ) { - assert.eq( prefix, str.substring( 0, prefix.length ) ); -} - /** @return count when hinting the index to use. */ function hintedCount( query ) { - assertPrefix( indexCursorName, t.find( query ).hint( indexKeySpec ).explain().cursor ); return t.find( query ).hint( indexKeySpec ).itcount(); } @@ -33,7 +26,6 @@ function assertMissing( query, expectedMissing, expectedIndexedMissing ) { expectedMissing = expectedMissing || 1; expectedIndexedMissing = expectedIndexedMissing || 0; assert.eq( expectedMissing, t.count( query ) ); - assert.eq( 'BasicCursor', t.find( query ).explain().cursor ); // We also shouldn't get a different count depending on whether // an index is used or not. assert.eq( expectedIndexedMissing, hintedCount( query ) ); @@ -43,14 +35,12 @@ function assertMissing( query, expectedMissing, expectedIndexedMissing ) { function assertExists( query, expectedExists ) { expectedExists = expectedExists || 2; assert.eq( expectedExists, t.count( query ) ); - assert.eq( 0, t.find( query ).explain().cursor.indexOf('BtreeCursor') ); // An $exists:true predicate generates no index filters. Add another predicate on the index key // to trigger use of the index. andClause = {} andClause[ indexKeyField ] = { $ne:null }; Object.extend( query, { $and:[ andClause ] } ); assert.eq( expectedExists, t.count( query ) ); - assertPrefix( indexCursorName, t.find( query ).explain().cursor ); assert.eq( expectedExists, hintedCount( query ) ); } @@ -58,13 +48,11 @@ function assertExists( query, expectedExists ) { function assertExistsUnindexed( query, expectedExists ) { expectedExists = expectedExists || 2; assert.eq( expectedExists, t.count( query ) ); - assert.eq( 'BasicCursor', t.find( query ).explain().cursor ); // Even with another predicate on the index key, the sparse index is disallowed. andClause = {} andClause[ indexKeyField ] = { $ne:null }; Object.extend( query, { $and:[ andClause ] } ); assert.eq( expectedExists, t.count( query ) ); - assert.eq( 'BasicCursor', t.find( query ).explain().cursor ); assert.eq( expectedExists, hintedCount( query ) ); } @@ -111,4 +99,3 @@ t.drop(); t.save( {} ); t.ensureIndex( { a:1 } ); assert.eq( 1, t.find( { a:{ $exists:false } } ).itcount() ); -assert.eq( 'BtreeCursor a_1', t.find( { a:{ $exists:false } } ).explain().cursor ); diff --git a/jstests/core/explain1.js b/jstests/core/explain1.js index e497bbfb9a9..59d29100507 100644 --- a/jstests/core/explain1.js +++ b/jstests/core/explain1.js @@ -18,31 +18,7 @@ assert.eq( 49 , t.find( q ).count() , "D" ); assert.eq( 49 , t.find( q ).itcount() , "E" ); assert.eq( 20 , t.find( q ).limit(20).itcount() , "F" ); -assert.eq( 49 , t.find(q).explain().n , "G" ); -assert.eq( 20 , t.find(q).limit(20).explain().n , "H" ); -assert.eq( 20 , t.find(q).limit(-20).explain().n , "I" ); -assert.eq( 49 , t.find(q).batchSize(20).explain().n , "J" ); - -// verbose explain output with stats -// display index bounds - -var explainGt = t.find({x: {$gt: 5}}).explain(true); -var boundsVerboseGt = explainGt.stats.inputStage.indexBounds; - -print('explain stats for $gt = ' + tojson(explainGt.stats)); - -var explainGte = t.find({x: {$gte: 5}}).explain(true); -var boundsVerboseGte = explainGte.stats.inputStage.indexBounds; - -print('explain stats for $gte = ' + tojson(explainGte.stats)); - -print('index bounds for $gt = ' + tojson(explainGt.indexBounds)); -print('index bounds for $gte = ' + tojson(explainGte.indexBounds)); - -print('verbose bounds for $gt = ' + tojson(boundsVerboseGt)); -print('verbose bounds for $gte = ' + tojson(boundsVerboseGte)); - -// Since the verbose bounds are opaque, all we try to confirm is that the -// verbose bounds for $gt is different from those generated for $gte. -assert.neq(boundsVerboseGt, boundsVerboseGte, - 'verbose bounds for $gt and $gte should not be the same'); +assert.eq( 49 , t.find(q).explain().executionStats.nReturned , "G" ); +assert.eq( 20 , t.find(q).limit(20).explain().executionStats.nReturned , "H" ); +assert.eq( 20 , t.find(q).limit(-20).explain().executionStats.nReturned , "I" ); +assert.eq( 49 , t.find(q).batchSize(20).explain().executionStats.nReturned , "J" ); diff --git a/jstests/core/explain2.js b/jstests/core/explain2.js index b70ffdc0b1e..799f5323598 100644 --- a/jstests/core/explain2.js +++ b/jstests/core/explain2.js @@ -1,27 +1,24 @@ +// Test calculation of the 'millis' field in explain output. -t = db.explain2 +t = db.jstests_explain2; t.drop(); -t.ensureIndex( { a : 1 , b : 1 } ); - -for ( i=1; i<10; i++ ){ - t.insert( { _id : i , a : i , b : i , c : i } ); +t.ensureIndex( { a:1 } ); +for( i = 1000; i < 4000; i += 1000 ) { + t.save( { a:i } ); } -function go( q , c , b , o ){ - var e = t.find( q ).hint( {a:1,b:1} ).explain(); - assert.eq( c , e.n , "count " + tojson( q ) ) - assert.eq( b , e.nscanned , "nscanned " + tojson( q ) ) - assert.eq( o , e.nscannedObjects , "nscannedObjects " + tojson( q ) ) +// Run a query with one $or clause per a-value, each of which sleeps for 'a' milliseconds. +function slow() { + sleep( this.a ); + return true; } +clauses = []; +for( i = 1000; i < 4000; i += 1000 ) { + clauses.push( { a:i, $where:slow } ); +} +explain = t.find( { $or:clauses } ).explain( true ); +printjson( explain ); -q = { a : { $gt : 3 } } -go( q , 6 , 6 , 6 ); - -q.b = 5 -go( q , 1 , 6 , 1 ); - -delete q.b -q.c = 5 -go( q , 1 , 6 , 6 ); - +// Verify the duration of the whole query, and of each clause. +assert.gt( explain.executionStats.executionTimeMillis, 1000 - 500 + 2000 - 500 + 3000 - 500 ); diff --git a/jstests/core/explain4.js b/jstests/core/explain4.js index d6d3d818a72..effd080d8fd 100644 --- a/jstests/core/explain4.js +++ b/jstests/core/explain4.js @@ -1,68 +1,18 @@ -// Basic validation of explain output fields. +// Test that limit is applied by explain. t = db.jstests_explain4; t.drop(); -function checkField( explain, name, value ) { - assert( explain.hasOwnProperty( name ) ); - if ( value != null ) { - assert.eq( value, explain[ name ], name ); - // Check that the value is of the expected type. SERVER-5288 - assert.eq( typeof( value ), typeof( explain[ name ] ), 'type ' + name ); - } -} - -function checkNonCursorPlanFields( explain, matches, n ) { - checkField( explain, "n", n ); - checkField( explain, "nscannedObjects", matches ); - checkField( explain, "nscanned", matches ); -} - -function checkPlanFields( explain, matches, n ) { - checkField( explain, "cursor", "BasicCursor" ); - // index related fields do not appear in non-indexed plan - assert(!("indexBounds" in explain)); - checkNonCursorPlanFields( explain, matches, n ); -} +t.ensureIndex( { a:1 } ); -function checkFields( matches, sort, limit ) { - cursor = t.find(); - if ( sort ) { - print("sort is {a:1}"); - cursor.sort({a:1}); - } - if ( limit ) { - print("limit = " + limit); - cursor.limit( limit ); - } - explain = cursor.explain( true ); - printjson( explain ); - checkPlanFields( explain, matches, matches > 0 ? 1 : 0 ); - checkField( explain, "scanAndOrder", sort ); - checkField( explain, "millis" ); - checkField( explain, "nYields" ); - checkField( explain, "nChunkSkips", 0 ); - checkField( explain, "isMultiKey", false ); - checkField( explain, "indexOnly", false ); - checkField( explain, "server" ); - checkField( explain, "allPlans" ); - explain.allPlans.forEach( function( x ) { checkPlanFields( x, matches, matches ); } ); +for( i = 0; i < 10; ++i ) { + t.save( { a:i, b:0 } ); } -checkFields( 0, false ); - -// If there's nothing in the collection, there's no point in verifying that a sort -// is done. -// checkFields( 0, true ); - -t.save( {} ); -checkFields( 1, false ); -checkFields( 1, true ); - -t.save( {} ); -checkFields( 1, false, 1 ); +explain = t.find( { a:{ $gte:0 }, b:0 } ).sort( { a:1 } ) + .hint( { a:1 } ) + .limit( 5 ) + .explain( true ); -// Check basic fields with multiple clauses. -t.save( { _id:0 } ); -explain = t.find( { $or:[ { _id:0 }, { _id:1 } ] } ).explain( true ); -checkNonCursorPlanFields( explain, 1, 1 ); +// Five results are expected, matching the limit spec. +assert.eq( 5, explain.executionStats.nReturned ); diff --git a/jstests/core/explain5.js b/jstests/core/explain5.js index cce6eab4fa4..22f8ae9f184 100644 --- a/jstests/core/explain5.js +++ b/jstests/core/explain5.js @@ -1,44 +1,29 @@ -// Check that the explain result count does proper deduping. +// Check explain results for a plan that uses an index to obtain the requested sort order. t = db.jstests_explain5; t.drop(); -t.ensureIndex( {a:1} ); -t.ensureIndex( {b:1} ); +t.ensureIndex( { a:1 } ); +t.ensureIndex( { b:1 } ); -t.save( {a:[1,2,3],b:[4,5,6]} ); -for( i = 0; i < 10; ++i ) { - t.save( {} ); +for( i = 0; i < 1000; ++i ) { + t.save( { a:i, b:i%3 } ); } -// Check with a single in order plan. +// Query with an initial set of documents. +var explain1 = t.find( { a:{ $gte:0 }, b:2 } ).sort( { a:1 } ).hint( { a:1 } ).explain(); +printjson(explain1); +var stats1 = explain1.executionStats; +assert.eq( 333, stats1.nReturned, 'wrong nReturned for explain1' ); +assert.eq( 1000, stats1.totalKeysExamined, 'wrong totalKeysExamined for explain1' ); -explain = t.find( {a:{$gt:0}} ).explain( true ); -assert.eq( 1, explain.n ); -assert.eq( 1, explain.allPlans[ 0 ].n ); - -// Check with a single out of order plan. - -explain = t.find( {a:{$gt:0}} ).sort( {z:1} ).hint( {a:1} ).explain( true ); -assert.eq( 1, explain.n ); -assert.eq( 1, explain.allPlans[ 0 ].n ); - -// Check with multiple plans. - -/* STAGE_MIGRATION: -// As part of 2.7 we plan to rework explain (see SERVER-10448 for details) -// so didn't carry over old behavior from multi_plan_runner into multi_plan stage -// Specifically, missing call to explainMultiPlan, so can't explain.allPlans[1].n below - -explain = t.find( {a:{$gt:0},b:{$gt:0}} ).explain( true ); -assert.eq( 1, explain.n ); -assert.eq( 1, explain.allPlans[ 0 ].n ); -assert.eq( 1, explain.allPlans[ 1 ].n ); - -explain = t.find( {$or:[{a:{$gt:0},b:{$gt:0}},{a:{$gt:-1},b:{$gt:-1}}]} ).explain( true ); -assert.eq( 1, explain.n ); -// Check 'n' for every alternative query plan. -for (var i = 0; i < explain.allPlans.length; ++i) { - assert.eq( 1, explain.allPlans[i].n ); +for( i = 1000; i < 2000; ++i ) { + t.save( { a:i, b:i%3 } ); } -*/ + +// Query with some additional documents. +var explain2 = t.find( { a:{ $gte:0 }, b:2 } ).sort( { a:1 } ).hint ( { a:1 } ).explain(); +printjson(explain2); +var stats2 = explain2.executionStats; +assert.eq( 666, stats2.nReturned, 'wrong nReturned for explain2' ); +assert.eq( 2000, stats2.totalKeysExamined, 'wrong totalKeysExamined for explain2' ); diff --git a/jstests/core/explain6.js b/jstests/core/explain6.js index 47d8d2fd731..7bcc09b8f2a 100644 --- a/jstests/core/explain6.js +++ b/jstests/core/explain6.js @@ -1,25 +1,35 @@ -// Test explain result count when a skip parameter is used. +// Basic test which checks the number of documents returned, keys examined, and documents +// examined as reported by explain. t = db.jstests_explain6; t.drop(); -t.save( {} ); -explain = t.find().skip( 1 ).explain( true ); -assert.eq( 0, explain.n ); -// With only one plan, the skip information is known for the plan. This is an arbitrary -// implementation detail, but it changes the way n is calculated. -assert.eq( 0, explain.allPlans[ 0 ].n ); - -t.ensureIndex( {a:1} ); -explain = t.find( {a:null,b:null} ).skip( 1 ).explain( true ); -assert.eq( 0, explain.n ); - -printjson( explain ); -assert.eq( 0, explain.allPlans[ 0 ].n ); - -t.dropIndexes(); -explain = t.find().skip( 1 ).sort({a:1}).explain( true ); -// Skip is applied for an in memory sort. -assert.eq( 0, explain.n ); -printjson(explain); -assert.eq( 0, explain.allPlans[ 0 ].n ); +t.ensureIndex( { a:1, b:1 } ); +t.ensureIndex( { b:1, a:1 } ); + +t.save( { a:0, b:1 } ); +t.save( { a:1, b:0 } ); + +explain = t.find( { a:{ $gte:0 }, b:{ $gte:0 } } ).explain( true ); + +assert.eq( 2, explain.executionStats.nReturned ); +assert.eq( 2, explain.executionStats.totalKeysExamined ); +assert.eq( 2, explain.executionStats.totalDocsExamined ); + +// A limit of 2. +explain = t.find( { a:{ $gte:0 }, b:{ $gte:0 } } ).limit( -2 ).explain( true ); +assert.eq( 2, explain.executionStats.nReturned ); + +// A $or query. +explain = t.find( { $or:[ { a:{ $gte:0 }, b:{ $gte:1 } }, + { a:{ $gte:1 }, b:{ $gte:0 } } ] } ).explain( true ); +assert.eq( 2, explain.executionStats.nReturned ); + +// A non $or case where totalKeysExamined != number of results +t.remove({}); + +t.save( { a:'0', b:'1' } ); +t.save( { a:'1', b:'0' } ); +explain = t.find( { a:/0/, b:/1/ } ).explain( true ); +assert.eq( 1, explain.executionStats.nReturned ); +assert.eq( 2, explain.executionStats.totalKeysExamined ); diff --git a/jstests/core/explain7.js b/jstests/core/explain7.js deleted file mode 100644 index f2850e56bea..00000000000 --- a/jstests/core/explain7.js +++ /dev/null @@ -1,193 +0,0 @@ -// Test cases for explain()'s nscannedObjects. SERVER-4161 - -t = db.jstests_explain7; -t.drop(); - -t.save( { a:1 } ); -t.ensureIndex( { a:1 } ); - -function assertExplain( expected, explain, checkAllPlans ) { - for( field in expected ) { - assert.eq( expected[ field ], explain[ field ], field ); - } - if ( checkAllPlans && explain.allPlans && explain.allPlans.length == 1 ) { - for( field in expected ) { - assert.eq( expected[ field ], explain.allPlans[ 0 ][ field ], field ); - } - } - return explain; -} - -function assertHintedExplain( expected, cursor ) { - return assertExplain( expected, cursor.hint( { a:1 } ).explain( true ), true ); -} - -function assertUnhintedExplain( expected, cursor, checkAllPlans ) { - return assertExplain( expected, cursor.explain( true ), checkAllPlans ); -} - -// Standard query. -assertHintedExplain( { n:1, nscanned:1, nscannedObjects:1 }, - t.find( { a:1 } ) ); - -// Covered index query. -assertHintedExplain( { n:1, nscanned:1, nscannedObjects:0 /* no object loaded */ }, - t.find( { a:1 }, { _id:0, a:1 } ) ); - -// Covered index query, but matching requires loading document. -assertHintedExplain( { n:1, nscanned:1, nscannedObjects:1 }, - t.find( { a:1, b:null }, { _id:0, a:1 } ) ); - -// $returnKey query. -assertHintedExplain( { n:1, nscanned:1, nscannedObjects:0 }, - t.find( { a:1 } )._addSpecial( "$returnKey", true ) ); - -// $returnKey query but matching requires loading document. -assertHintedExplain( { n:1, nscanned:1, nscannedObjects:1 }, - t.find( { a:1, b:null } )._addSpecial( "$returnKey", true ) ); - -// Skip a result. -assertHintedExplain( { n:0, nscanned:1, nscannedObjects:1 }, - t.find( { a:1 } ).skip( 1 ) ); - -// Cursor sorted covered index query. -assertHintedExplain( { n:1, nscanned:1, nscannedObjects:0, scanAndOrder:false }, - t.find( { a:1 }, { _id:0, a:1 } ).sort( { a:1 } ) ); - -t.dropIndex( { a:1 } ); -t.ensureIndex( { a:1, b:1 } ); - -// In memory sort covered index query. -assertUnhintedExplain( { n:1, nscanned:1, nscannedObjects:1, scanAndOrder:true }, - t.find( { a:{ $gt:0 } }, { _id:0, a:1 } ).sort( { b:1 } ) - .hint( { a:1, b:1 } ) ); - -// In memory sort $returnKey query. -assertUnhintedExplain( { n:1, nscanned:1, scanAndOrder:true }, - t.find( { a:{ $gt:0 } } )._addSpecial( "$returnKey", true ).sort( { b:1 } ) - .hint( { a:1, b:1 } ) ); - -// In memory sort with skip. -assertUnhintedExplain( { n:0, nscanned:1, nscannedObjects:1 /* The record is still loaded. */ }, - t.find( { a:{ $gt:0 } } ).sort( { b:1 } ).skip( 1 ).hint( { a:1, b:1 } ), - false ); - -// With a multikey index. -t.drop(); -t.ensureIndex( { a:1 } ); -t.save( { a:[ 1, 2 ] } ); - -assertHintedExplain( { n:1, scanAndOrder:false }, - t.find( { a:{ $gt:0 } }, { _id:0, a:1 } ) ); -assertHintedExplain( { n:1, scanAndOrder:true }, - t.find( { a:{ $gt:0 } }, { _id:0, a:1 } ).sort( { b:1 } ) ); - -// Dedup matches from multiple query plans. -t.drop(); -t.ensureIndex( { a:1, b:1 } ); -t.ensureIndex( { b:1, a:1 } ); -t.save( { a:1, b:1 } ); - -// Document matched by three query plans. -assertUnhintedExplain( { n:1, nscanned:1, nscannedObjects:1 }, - t.find( { a:{ $gt:0 }, b:{ $gt:0 } } ) ); - -// Document matched by three query plans, with sorting. -assertUnhintedExplain( { n:1, nscanned:1, nscannedObjects:1 }, - t.find( { a:{ $gt:0 }, b:{ $gt:0 } } ).sort( { c:1 } ) ); - -// Document matched by three query plans, with a skip. -assertUnhintedExplain( { n:0, nscanned:1, nscannedObjects:1 }, - t.find( { a:{ $gt:0 }, b:{ $gt:0 } } ).skip( 1 ) ); - -// Hybrid ordered and unordered plans. - -t.drop(); -t.ensureIndex( { a:1, b:1 } ); -t.ensureIndex( { b:1 } ); -for( i = 0; i < 30; ++i ) { - t.save( { a:i, b:i } ); -} - -// Ordered plan chosen. -assertUnhintedExplain( { cursor:'BtreeCursor a_1_b_1', n:30, nscanned:30, nscannedObjects:30, - scanAndOrder:false }, - t.find( { b:{ $gte:0 } } ).sort( { a:1 } ) ); - -// SERVER-12769: When an index is used to provide a sort, our covering -// analysis isn't good. This could execute as a covered query, but currently -// does not. -/* -// Ordered plan chosen with a covered index. -//assertUnhintedExplain( { cursor:'BtreeCursor a_1_b_1', n:30, nscanned:30, nscannedObjects:0, - //scanAndOrder:false }, - //t.find( { b:{ $gte:0 } }, { _id:0, b:1 } ).sort( { a:1 } ) ); -*/ - -// Ordered plan chosen, with a skip. Skip is not included in counting nscannedObjects for a single -// plan. -assertUnhintedExplain( { cursor:'BtreeCursor a_1_b_1', n:29, nscanned:30, nscannedObjects:30, - scanAndOrder:false }, - t.find( { b:{ $gte:0 } } ).sort( { a:1 } ).skip( 1 ) ); - -// Unordered plan chosen. -assertUnhintedExplain( { cursor:'BtreeCursor b_1', n:1, nscanned:1, - //nscannedObjects:1, nscannedObjectsAllPlans:2, - scanAndOrder:true }, - t.find( { b:1 } ).sort( { a:1 } ) ); - -// Unordered plan chosen and projected. -assertUnhintedExplain( { cursor:'BtreeCursor b_1', n:1, nscanned:1, nscannedObjects:1, - scanAndOrder:true }, - t.find( { b:1 }, { _id:0, b:1 } ).sort( { a:1 } ) ); - -// Unordered plan chosen, with a skip. -// Note that all plans are equally unproductive here, so we can't test which one is picked reliably. -assertUnhintedExplain( { n:0 }, - t.find( { b:1 }, { _id:0, b:1 } ).sort( { a:1 } ).skip( 1 ) ); - -// Unordered plan chosen, $returnKey specified. -assertUnhintedExplain( { cursor:'BtreeCursor b_1', n:1, nscanned:1, scanAndOrder:true }, - t.find( { b:1 }, { _id:0, b:1 } ).sort( { a:1 } ) - ._addSpecial( "$returnKey", true ) ); - -// Unordered plan chosen, $returnKey specified, matching requires loading document. -assertUnhintedExplain( { cursor:'BtreeCursor b_1', n:1, nscanned:1, nscannedObjects:1, - scanAndOrder:true }, - t.find( { b:1, c:null }, { _id:0, b:1 } ).sort( { a:1 } ) - ._addSpecial( "$returnKey", true ) ); - -t.ensureIndex( { a:1, b:1, c:1 } ); - -// Documents matched by four query plans. -assertUnhintedExplain( { n:30, nscanned:30, nscannedObjects:30, - //nscannedObjectsAllPlans:90 // Not 120 because deduping occurs before - // loading results. - }, - t.find( { a:{ $gte:0 }, b:{ $gte:0 } } ).sort( { b:1 } ) ); - -for( i = 30; i < 150; ++i ) { - t.save( { a:i, b:i } ); -} - -// Non-covered $or query. -explain = assertUnhintedExplain( { n:150, nscannedObjects:300 }, - t.find( { $or:[ { a:{ $gte:-1, $lte:200 }, - b:{ $gte:0, $lte:201 } }, - { a:{ $gte:0, $lte:201 }, - b:{ $gte:-1, $lte:200 } } ] }, - { _id:1, a:1, b:1 } ).hint( { a:1, b:1 } ) ); -printjson(explain); -assert.eq( 150, explain.clauses[ 0 ].nscannedObjects ); -assert.eq( 150, explain.clauses[ 1 ].nscannedObjects ); - -// Covered $or query. -explain = assertUnhintedExplain( { n:150, nscannedObjects:0 }, - t.find( { $or:[ { a:{ $gte:-1, $lte:200 }, - b:{ $gte:0, $lte:201 } }, - { a:{ $gte:0, $lte:201 }, - b:{ $gte:-1, $lte:200 } } ] }, - { _id:0, a:1, b:1 } ).hint( { a:1, b:1 } ) ); -printjson(explain); -assert.eq( 0, explain.clauses[ 0 ].nscannedObjects ); -assert.eq( 0, explain.clauses[ 1 ].nscannedObjects ); diff --git a/jstests/core/explain8.js b/jstests/core/explain8.js deleted file mode 100644 index fde6adbd8f4..00000000000 --- a/jstests/core/explain8.js +++ /dev/null @@ -1,24 +0,0 @@ -// Test calculation of the 'millis' field in explain output. - -t = db.jstests_explain8; -t.drop(); - -t.ensureIndex( { a:1 } ); -for( i = 1000; i < 4000; i += 1000 ) { - t.save( { a:i } ); -} - -// Run a query with one $or clause per a-value, each of which sleeps for 'a' milliseconds. -function slow() { - sleep( this.a ); - return true; -} -clauses = []; -for( i = 1000; i < 4000; i += 1000 ) { - clauses.push( { a:i, $where:slow } ); -} -explain = t.find( { $or:clauses } ).explain( true ); -//printjson( explain ); - -// Verify the duration of the whole query, and of each clause. -assert.gt( explain.millis, 1000 - 500 + 2000 - 500 + 3000 - 500 ); diff --git a/jstests/core/explain9.js b/jstests/core/explain9.js deleted file mode 100644 index 80cab856aa7..00000000000 --- a/jstests/core/explain9.js +++ /dev/null @@ -1,24 +0,0 @@ -// Test that limit is applied by explain when there are both in order and out of order candidate -// plans. SERVER-4150 - -t = db.jstests_explain9; -t.drop(); - -t.ensureIndex( { a:1 } ); - -for( i = 0; i < 10; ++i ) { - t.save( { a:i, b:0 } ); -} - -explain = t.find( { a:{ $gte:0 }, b:0 } ).sort( { a:1 } ).limit( 5 ).explain( true ); -// Five results are expected, matching the limit spec. -assert.eq( 5, explain.n ); -explain.allPlans.forEach( function( x ) { - // Five results are expected for the in order plan. - if ( x.cursor == "BtreeCursor a_1" ) { - assert.eq( 5, x.n ); - } - else { - assert.gte( 5, x.n ); - } - } ); diff --git a/jstests/core/explain_batch_size.js b/jstests/core/explain_batch_size.js index 65bc1df40d7..1722052c233 100644 --- a/jstests/core/explain_batch_size.js +++ b/jstests/core/explain_batch_size.js @@ -7,13 +7,13 @@ t = db.explain_batch_size; t.drop(); -n = 3 +var n = 3 for (i=0; i<n; i++) { t.save( { x : i } ); } -q = {}; +var q = {}; assert.eq( n , t.find( q ).count() , "A" ); assert.eq( n , t.find( q ).itcount() , "B" ); -assert.eq( n , t.find( q ).batchSize(1).explain().n , "C" ); +assert.eq( n , t.find( q ).batchSize(1).explain().executionStats.nReturned , "C" ); diff --git a/jstests/core/explaina.js b/jstests/core/explaina.js deleted file mode 100644 index 65be1f7bc27..00000000000 --- a/jstests/core/explaina.js +++ /dev/null @@ -1,28 +0,0 @@ -// Check explain results when an in order plan is selected among mixed in order and out of order -// plans. - -t = db.jstests_explaina; -t.drop(); - -t.ensureIndex( { a:1 } ); -t.ensureIndex( { b:1 } ); - -for( i = 0; i < 1000; ++i ) { - t.save( { a:i, b:i%3 } ); -} - -// Query with an initial set of documents. -explain1 = t.find( { a:{ $gte:0 }, b:2 } ).sort( { a:1 } ).hint( { a:1 } ).explain(); -printjson(explain1); -assert.eq( 333, explain1.n, 'wrong n for explain1' ); -assert.eq( 1000, explain1.nscanned, 'wrong nscanned for explain1' ); - -for( i = 1000; i < 2000; ++i ) { - t.save( { a:i, b:i%3 } ); -} - -// Query with some additional documents. -explain2 = t.find( { a:{ $gte:0 }, b:2 } ).sort( { a:1 } ).hint ( { a:1 } ).explain(); -printjson(explain2); -assert.eq( 666, explain2.n, 'wrong n for explain2' ); -assert.eq( 2000, explain2.nscanned, 'wrong nscanned for explain2' ); diff --git a/jstests/core/explainb.js b/jstests/core/explainb.js deleted file mode 100644 index ab49a38ca72..00000000000 --- a/jstests/core/explainb.js +++ /dev/null @@ -1,46 +0,0 @@ -// nscanned and nscannedObjects report results for the winning plan; nscannedAllPlans and -// nscannedObjectsAllPlans report results for all plans. SERVER-6268 -// -// This file tests the output of .explain. - -t = db.jstests_explainb; -t.drop(); - -t.ensureIndex( { a:1, b:1 } ); -t.ensureIndex( { b:1, a:1 } ); - -t.save( { a:0, b:1 } ); -t.save( { a:1, b:0 } ); - -explain = t.find( { a:{ $gte:0 }, b:{ $gte:0 } } ).explain( true ); - -// We don't check explain.cursor because all plans perform the same. -assert.eq( 2, explain.n ); -// nscanned and nscannedObjects are reported. -assert.eq( 2, explain.nscanned ); -assert.eq( 2, explain.nscannedObjects ); - -// A limit of 2. -explain = t.find( { a:{ $gte:0 }, b:{ $gte:0 } } ).limit( -2 ).explain( true ); -assert.eq( 2, explain.n ); - -// A $or query. -explain = t.find( { $or:[ { a:{ $gte:0 }, b:{ $gte:1 } }, - { a:{ $gte:1 }, b:{ $gte:0 } } ] } ).explain( true ); -// One result from the first $or clause -assert.eq( 1, explain.clauses[ 0 ].n ); -// But 2 total. -assert.eq( 2, explain.n ); - -// These are computed by summing the values for each clause. -printjson(explain); -assert.eq( 2, explain.n ); - -// A non $or case where nscanned != number of results -t.remove({}); - -t.save( { a:'0', b:'1' } ); -t.save( { a:'1', b:'0' } ); -explain = t.find( { a:/0/, b:/1/ } ).explain( true ); -assert.eq( 1, explain.n ); -assert.eq( 2, explain.nscanned ); diff --git a/jstests/core/find8.js b/jstests/core/find8.js index 60f66a500e3..3622eba8ae6 100644 --- a/jstests/core/find8.js +++ b/jstests/core/find8.js @@ -21,7 +21,3 @@ t.find( { a: { $gt:5,$lt:2} } ).itcount(); // Check that we can record a plan for an 'invalid' range. assert( t.find( { a: { $gt:5,$lt:2} } ).explain( true ).oldPlan ); } - -t.ensureIndex( {b:1} ); -// Check that if we do a table scan of an 'invalid' range in an or clause we don't check subsequent clauses. -assert.eq( "BasicCursor", t.find( { $or:[{ a: { $gt:5,$lt:2} }, {b:1}] } ).explain().cursor ); diff --git a/jstests/core/fts_explain.js b/jstests/core/fts_explain.js index bbb933fa12e..263e4b04b38 100644 --- a/jstests/core/fts_explain.js +++ b/jstests/core/fts_explain.js @@ -11,9 +11,9 @@ res = coll.insert({content: "some data"}); assert.writeOK(res); var explain = coll.find({$text:{$search: "\"a\" -b -\"c\""}}).explain(true); -assert.eq(explain.cursor, "TextCursor"); -assert.eq(explain.stats.stage, "TEXT"); -assert.eq(explain.stats.parsedTextQuery.terms, ["a"]); -assert.eq(explain.stats.parsedTextQuery.negatedTerms, ["b"]); -assert.eq(explain.stats.parsedTextQuery.phrases, ["a"]); -assert.eq(explain.stats.parsedTextQuery.negatedPhrases, ["c"]); +var stage = explain.executionStats.executionStages; +assert.eq(stage.stage, "TEXT"); +assert.eq(stage.parsedTextQuery.terms, ["a"]); +assert.eq(stage.parsedTextQuery.negatedTerms, ["b"]); +assert.eq(stage.parsedTextQuery.phrases, ["a"]); +assert.eq(stage.parsedTextQuery.negatedPhrases, ["c"]); diff --git a/jstests/core/geo_2d_explain.js b/jstests/core/geo_2d_explain.js index c9bfe624436..f1a1e2887e4 100644 --- a/jstests/core/geo_2d_explain.js +++ b/jstests/core/geo_2d_explain.js @@ -24,5 +24,5 @@ var explain = t.find({loc: {$near: [40, 40]}, _id: {$lt: 50}}).explain(); print('explain = ' + tojson(explain)); -assert.eq(explain.n, explain.nscannedObjects); -assert.lte(explain.n, explain.nscanned); +var stats = explain.executionStats; +assert.eq(stats.nReturned, stats.totalDocsExamined); diff --git a/jstests/core/geo_box2.js b/jstests/core/geo_box2.js index 1ebe5843bd7..dd114ae5c2e 100644 --- a/jstests/core/geo_box2.js +++ b/jstests/core/geo_box2.js @@ -16,11 +16,3 @@ t.dropIndex( { "loc" : "2d" } ) t.ensureIndex({"loc" : "2d"} , {"min" : 0, "max" : 10}) assert.eq( 9 , t.find({loc : {$within : {$box : [[4,4],[6,6]]}}}).itcount() , "B1" ); - -// 'indexBounds.loc' in explain output should be filled in with at least -// one bounding box. -// Actual values is dependent on implementation of 2d execution stage. -var explain = t.find({loc : {$within : {$box : [[4,4],[6,6]]}}}).explain(true); -print( 'explain = ' + tojson(explain) ); -assert.neq( undefined, explain.indexBounds.loc, "C1" ); -assert.gt( explain.indexBounds.loc.length, 0, "C2" ); diff --git a/jstests/core/geo_center_sphere1.js b/jstests/core/geo_center_sphere1.js index 8beff537d12..a0539965ccc 100644 --- a/jstests/core/geo_center_sphere1.js +++ b/jstests/core/geo_center_sphere1.js @@ -89,7 +89,7 @@ function test(index) { print( 'explain for ' + tojson( q , '' , true ) + ' = ' + tojson( explain ) ); // The index should be at least minimally effective in preventing the full collection // scan. - assert.gt( t.find().count(), explain.nscanned , + assert.gt( t.find().count(), explain.executionStats.totalKeysExamined , "nscanned : " + tojson( searches[i] ) ) } } diff --git a/jstests/core/geo_circle1.js b/jstests/core/geo_circle1.js index 4a8a83218ab..d74e6a1eea3 100644 --- a/jstests/core/geo_circle1.js +++ b/jstests/core/geo_circle1.js @@ -41,5 +41,6 @@ for ( i=0; i<searches.length; i++ ){ print( 'explain for ' + tojson( q , '' , true ) + ' = ' + tojson( explain ) ); // The index should be at least minimally effective in preventing the full collection // scan. - assert.gt( t.find().count(), explain.nscanned , "nscanned : " + tojson( searches[i] ) ); + assert.gt( t.find().count(), explain.executionStats.totalKeysExamined, + "nscanned : " + tojson( searches[i] ) ); } diff --git a/jstests/core/geo_s2nearComplex.js b/jstests/core/geo_s2nearComplex.js index 835dfe88481..9c6ac0098be 100644 --- a/jstests/core/geo_s2nearComplex.js +++ b/jstests/core/geo_s2nearComplex.js @@ -164,7 +164,7 @@ uniformPoints(origin, 1000, 0.5, 1.5); validateOrdering({geo: {$geoNear: {$geometry: originGeo}}}) print("Millis for uniform:") -print(t.find(query).explain().millis) +print(t.find(query).explain().executionStats.executionTimeMillis); print("Total points:"); print(t.find(query).itcount()); @@ -176,7 +176,7 @@ uniformPointsWithGaps(origin, 1000, 1, 10.0, 5, 10); validateOrdering({geo: {$geoNear: {$geometry: originGeo}}}) print("Millis for uniform with gaps:") -print(t.find(query).explain().millis) +print(t.find(query).explain().executionStats.executionTimeMillis); print("Total points:"); print(t.find(query).itcount()); @@ -189,7 +189,7 @@ uniformPointsWithClusters(origin, 1000, 1, 10.0, 5, 10, 100); validateOrdering({geo: {$geoNear: {$geometry: originGeo}}}) print("Millis for uniform with clusters:"); -print(t.find(query).explain().millis); +print(t.find(query).explain().executionStats.executionTimeMillis); print("Total points:"); print(t.find(query).itcount()); @@ -209,7 +209,8 @@ uniformPoints(origin, 50, 0.5, 1.5); validateOrdering({geo: {$geoNear: {$geometry: originGeo}}}) print("Millis for uniform near pole:") -print(t.find({geo: {$geoNear: {$geometry: originGeo}}}).explain().millis) +print(t.find({geo: {$geoNear: {$geometry: originGeo}}}) + .explain().executionStats.executionTimeMillis); assert.eq(t.find({geo: {$geoNear: {$geometry: originGeo}}}).itcount(), 50); t.drop() @@ -226,7 +227,8 @@ uniformPoints(origin, 50, 0.5, 1.5); validateOrdering({geo: {$geoNear: {$geometry: originGeo}}}) print("Millis for uniform on meridian:") -print(t.find({geo: {$near: {$geometry: originGeo}}}).explain().millis) +print(t.find({geo: {$geoNear: {$geometry: originGeo}}}) + .explain().executionStats.executionTimeMillis); assert.eq(t.find({geo: {$geoNear: {$geometry: originGeo}}}).itcount(), 50); t.drop() @@ -243,7 +245,8 @@ uniformPoints(origin, 50, 0.5, 1.5); validateOrdering({geo: {$near: {$geometry: originGeo}}}) print("Millis for uniform on negative meridian:"); -print(t.find({geo: {$near: {$geometry: originGeo}}}).explain().millis); +print(t.find({geo: {$geoNear: {$geometry: originGeo}}}) + .explain().executionStats.executionTimeMillis); assert.eq(t.find({geo: {$near: {$geometry: originGeo}}}).itcount(), 50); // Near search with points that are really far away. @@ -263,6 +266,7 @@ assert.eq(cur.itcount(), 10); cur = t.find({geo: {$near: {$geometry: originGeo}}}) print("Near search on very distant points:"); -print(t.find({geo: {$near: {$geometry: originGeo}}}).explain().millis); +print(t.find({geo: {$geoNear: {$geometry: originGeo}}}) + .explain().executionStats.executionTimeMillis); pt = cur.next(); assert(pt) diff --git a/jstests/core/geo_s2ordering.js b/jstests/core/geo_s2ordering.js index 13847b08745..3dd75ff5785 100644 --- a/jstests/core/geo_s2ordering.js +++ b/jstests/core/geo_s2ordering.js @@ -35,8 +35,8 @@ function runTest(index) { iterations = 10; for (var x = 0; x < iterations; ++x) { res = t.find({nongeo: needle, geo: {$within: {$centerSphere: [[0,0], Math.PI/180.0]}}}) - if (res.explain().millis < mintime) { - mintime = res.explain().millis + if (res.explain().executionStats.executionTimeMillis < mintime) { + mintime = res.explain().executionStats.executionTimeMillis; resultcount = res.itcount() } } diff --git a/jstests/core/geo_s2twofields.js b/jstests/core/geo_s2twofields.js index 1ee7d8d289f..039223aadcf 100644 --- a/jstests/core/geo_s2twofields.js +++ b/jstests/core/geo_s2twofields.js @@ -42,9 +42,13 @@ function semiRigorousTime(func) { function timeWithoutAndWithAnIndex(index, query) { t.dropIndex(index); - var withoutTime = semiRigorousTime(function() { return t.find(query).explain().millis; }); + var withoutTime = semiRigorousTime(function() { + return t.find(query).explain().executionStats.executionTimeMillis; + }); t.ensureIndex(index); - var withTime = semiRigorousTime(function() { return t.find(query).explain().millis; }); + var withTime = semiRigorousTime(function() { + return t.find(query).explain().executionStats.executionTimeMillis; + }); t.dropIndex(index); return [withoutTime, withTime]; } diff --git a/jstests/core/hashindex1.js b/jstests/core/hashindex1.js index 34bd6dc0725..dcb75dafaf1 100644 --- a/jstests/core/hashindex1.js +++ b/jstests/core/hashindex1.js @@ -1,6 +1,9 @@ var t = db.hashindex1; t.drop() +// Include helpers for analyzing explain output. +load("jstests/libs/analyze_plan.js"); + //test non-single field hashed indexes don't get created (maybe change later) var badspec = {a : "hashed" , b : 1}; t.ensureIndex( badspec ); @@ -34,36 +37,30 @@ assert.eq( t.find({a : 3}).hint(goodspec).toArray().length , 1); //test right obj is found assert.eq( t.find({a : 3.1}).hint(goodspec).toArray()[0].a , 3.1); -//test that hashed cursor is used when it should be -var cursorname = "BtreeCursor a_hashed"; -assert.eq( t.find({a : 1}).explain().cursor , - cursorname , - "not using hashed cursor"); +// Make sure we're using the hashed index. +var explain = t.find({a : 1}).explain(); +assert( isIxscan(explain.queryPlanner.winningPlan), "not using hashed index"); // SERVER-12222 //printjson( t.find({a : {$gte : 3 , $lte : 3}}).explain() ) //assert.eq( t.find({a : {$gte : 3 , $lte : 3}}).explain().cursor , // cursorname , // "not using hashed cursor"); -assert.neq( t.find({c : 1}).explain().cursor , - cursorname , - "using irrelevant hashed cursor"); +var explain = t.find({c : 1}).explain(); +assert( !isIxscan(explain.queryPlanner.winningPlan), "using irrelevant hashed index"); -printjson( t.find({a : {$in : [1,2]}}).explain() ) // Hash index used with a $in set membership predicate. -assert.eq( t.find({a : {$in : [1,2]}}).explain()["cursor"], - "BtreeCursor a_hashed", - "not using hashed cursor"); +var explain = t.find({a : {$in : [1,2]}}).explain(); +printjson(explain); +assert( isIxscan(explain.queryPlanner.winningPlan), "not using hashed index"); // Hash index used with a singleton $and predicate conjunction. -assert.eq( t.find({$and : [{a : 1}]}).explain()["cursor"], - "BtreeCursor a_hashed", - "not using hashed cursor"); +var explain = t.find({$and : [{a : 1}]}).explain(); +assert( isIxscan(explain.queryPlanner.winningPlan), "not using hashed index"); // Hash index used with a non singleton $and predicate conjunction. -assert.eq( t.find({$and : [{a : {$in : [1,2]}},{a : {$gt : 1}}]}).explain()["cursor"], - "BtreeCursor a_hashed", - "not using hashed cursor"); +var explain = t.find({$and : [{a : {$in : [1,2]}},{a : {$gt : 1}}]}).explain(); +assert( isIxscan(explain.queryPlanner.winningPlan), "not using hashed index"); //test creation of index based on hash of _id index var goodspec2 = {'_id' : "hashed"}; diff --git a/jstests/core/hint1.js b/jstests/core/hint1.js index b5a580f2b93..1de06fd4e41 100644 --- a/jstests/core/hint1.js +++ b/jstests/core/hint1.js @@ -1,16 +1,7 @@ - p = db.jstests_hint1; p.drop(); p.save( { ts: new Date( 1 ), cls: "entry", verticals: "alleyinsider", live: true } ); p.ensureIndex( { ts: 1 } ); -e = p.find( { live: true, ts: { $lt: new Date( 1234119308272 ) }, cls: "entry", verticals: "alleyinsider" } ).sort( { ts: -1 } ).hint( { ts: 1 } ).explain(); -assert.eq(e.indexBounds.ts[0][0].getTime(), new Date(1234119308272).getTime(), "A"); - -//printjson(e); - -assert.eq( /*just below min date is bool true*/true, e.indexBounds.ts[0][1], "B"); - assert.eq(1, p.find({ live: true, ts: { $lt: new Date(1234119308272) }, cls: "entry", verticals: "alleyinsider" }).sort({ ts: -1 }).hint({ ts: 1 }).count()); - diff --git a/jstests/core/idhack.js b/jstests/core/idhack.js index e40c043d455..fa9ed5287c6 100644 --- a/jstests/core/idhack.js +++ b/jstests/core/idhack.js @@ -2,6 +2,8 @@ t = db.idhack t.drop() +// Include helpers for analyzing explain output. +load("jstests/libs/analyze_plan.js"); t.insert( { _id : { x : 1 } , z : 1 } ) t.insert( { _id : { x : 2 } , z : 2 } ) @@ -26,28 +28,25 @@ assert.eq( 8 , t.findOne( { _id : 3 } ).z , "C3" ) var query = { _id : { x : 2 } }; var explain = t.find( query ).explain( true ); print( "explain for " + tojson( query , "" , true ) + " = " + tojson( explain ) ); -assert.eq( 1 , explain.n , "D1" ); -assert.eq( 1 , explain.nscanned , "D2" ); -assert.neq( undefined , explain.cursor , "D3" ); -assert.neq( "" , explain.cursor , "D4" ); +assert.eq( 1 , explain.executionStats.nReturned , "D1" ); +assert.eq( 1 , explain.executionStats.totalKeysExamined , "D2" ); +assert( isIdhack(explain.queryPlanner.winningPlan), "D3" ); // ID hack cannot be used with hint(). -var query = { _id : { x : 2 } }; -var explain = t.find( query ).explain(); t.ensureIndex( { _id : 1 , a : 1 } ); var hintExplain = t.find( query ).hint( { _id : 1 , a : 1 } ).explain(); print( "explain for hinted query = " + tojson( hintExplain ) ); -assert.neq( explain.cursor, hintExplain.cursor, "E1" ); +assert( !isIdhack(hintExplain.queryPlanner.winningPlan), "E1" ); // ID hack cannot be used with skip(). var skipExplain = t.find( query ).skip(1).explain(); print( "explain for skip query = " + tojson( skipExplain ) ); -assert.neq( explain.cursor, skipExplain.cursor, "F1" ); +assert( !isIdhack(skipExplain.queryPlanner.winningPlan), "F1" ); // Covered query returning _id field only can be handled by ID hack. var coveredExplain = t.find( query, { _id : 1 } ).explain(); print( "explain for covered query = " + tojson( coveredExplain ) ); -assert.eq( explain.cursor, coveredExplain.cursor, "G1" ); +assert( isIdhack(coveredExplain.queryPlanner.winningPlan), "G1" ); // Check doc from covered ID hack query. assert.eq( { _id : { x: 2 } }, t.findOne( query, { _id : 1 } ), "G2" ); diff --git a/jstests/core/in3.js b/jstests/core/in3.js index b0a8bb7b81f..5e7e587629f 100644 --- a/jstests/core/in3.js +++ b/jstests/core/in3.js @@ -1,11 +1,23 @@ -t = db.jstests_in3; +// SERVER-2829 Test arrays matching themselves within a $in expression. -t.drop(); -t.ensureIndex( {i:1} ); -assert.eq( {i:[[3,3]]}, t.find( {i:{$in:[3]}} ).explain().indexBounds , "A1" ); -assert.eq( {i:[[3,3],[6,6]]}, t.find( {i:{$in:[3,6]}} ).explain().indexBounds , "A2" ); +t = db.jstests_in8; +t.drop(); -for ( var i=0; i<20; i++ ) - t.insert( { i : i } ); +t.save( {key: [1]} ); +t.save( {key: ['1']} ); +t.save( {key: [[2]]} ); -assert.eq( 3 , t.find( {i:{$in:[3,6]}} ).explain().nscanned , "B1" ) +function doTest() { + assert.eq( 1, t.count( {key:[1]} ) ); + assert.eq( 1, t.count( {key:{$in:[[1]]}} ) ); + assert.eq( 1, t.count( {key:{$in:[[1]],$ne:[2]}} ) ); + assert.eq( 1, t.count( {key:{$in:[['1']],$type:2}} ) ); + assert.eq( 1, t.count( {key:['1']} ) ); + assert.eq( 1, t.count( {key:{$in:[['1']]}} ) ); + assert.eq( 1, t.count( {key:[2]} ) ); + assert.eq( 1, t.count( {key:{$in:[[2]]}} ) ); +} + +doTest(); +t.ensureIndex( {key:1} ); +doTest(); diff --git a/jstests/core/in4.js b/jstests/core/in4.js index 3e3dca29528..cbe28e2e2df 100644 --- a/jstests/core/in4.js +++ b/jstests/core/in4.js @@ -1,42 +1,35 @@ -t = db.jstests_in4; +// SERVER-2343 Test $in empty array matching. -function checkRanges( a, b ) { - assert.eq( a, b ); -} +t = db.jstests_in9; +t.drop(); -t.drop(); -t.ensureIndex( {a:1,b:1} ); -checkRanges( {a:[[2,2]],b:[[3,3]]}, t.find( {a:2,b:3} ).explain().indexBounds ); -checkRanges( {a:[[2,2],[3,3]],b:[[4,4]]}, t.find( {a:{$in:[2,3]},b:4} ).explain().indexBounds ); -checkRanges( {a:[[2,2]],b:[[3,3],[4,4]]}, t.find( {a:2,b:{$in:[3,4]}} ).explain().indexBounds ); -checkRanges( {a:[[2,2],[3,3]],b:[[4,4],[5,5]]}, t.find( {a:{$in:[2,3]},b:{$in:[4,5]}} ).explain().indexBounds ); +function someData() { + t.remove({}); + t.save( {key: []} ); +} -checkRanges( {a:[[2,2],[3,3]],b:[[4,10]]}, t.find( {a:{$in:[2,3]},b:{$gt:4,$lt:10}} ).explain().indexBounds ); +function moreData() { + someData(); + t.save( {key: [1]} ); + t.save( {key: ['1']} ); + t.save( {key: null} ); + t.save( {} ); +} -t.save( {a:1,b:1} ); -t.save( {a:2,b:4.5} ); -t.save( {a:2,b:4} ); -assert.eq( 2, t.find( {a:{$in:[2,3]},b:{$in:[4,5]}} ).hint( {a:1,b:1} ).explain().nscanned ); -assert.eq( 2, t.findOne( {a:{$in:[2,3]},b:{$in:[4,5]}} ).a ); -assert.eq( 4, t.findOne( {a:{$in:[2,3]},b:{$in:[4,5]}} ).b ); +function check() { + assert.eq( 1, t.count( {key:[]} ) ); + assert.eq( 1, t.count( {key:{$in:[[]]}} ) ); +} -t.drop(); -t.ensureIndex( {a:1,b:1,c:1} ); -checkRanges( {a:[[2,2]],b:[[3,3],[4,4]],c:[[5,5]]}, t.find( {a:2,b:{$in:[3,4]},c:5} ).explain().indexBounds ); +function doTest() { + someData(); + check(); + moreData(); + check(); +} -t.save( {a:2,b:3,c:5} ); -t.save( {a:2,b:3,c:4} ); -assert.eq( 1, t.find( {a:2,b:{$in:[3,4]},c:5} ).hint( {a:1,b:1,c:1} ).explain().nscanned ); -t.remove({}); -t.save( {a:2,b:4,c:5} ); -t.save( {a:2,b:4,c:4} ); -assert.eq( 2, t.find( {a:2,b:{$in:[3,4]},c:5} ).hint( {a:1,b:1,c:1} ).explain().nscanned ); +doTest(); -t.drop(); -t.ensureIndex( {a:1,b:-1} ); -ib = t.find( {a:2,b:{$in:[3,4]}} ).explain().indexBounds; -checkRanges( {a:[[2,2]],b:[[4,4],[3,3]]}, ib ); -assert( ib.b[ 0 ][ 0 ] > ib.b[ 1 ][ 0 ] ); -ib = t.find( {a:2,b:{$in:[3,4]}} ).sort( {a:-1,b:1} ).explain().indexBounds; -checkRanges( {a:[[2,2]],b:[[3,3],[4,4]]}, ib ); -assert( ib.b[ 0 ][ 0 ] < ib.b[ 1 ][ 0 ] ); +// SERVER-1943 not fixed yet +t.ensureIndex( {key:1} ); +doTest(); diff --git a/jstests/core/ina.js b/jstests/core/in7.js index cf614ab994d..cf614ab994d 100644 --- a/jstests/core/ina.js +++ b/jstests/core/in7.js diff --git a/jstests/core/in8.js b/jstests/core/in8.js index 5e7e587629f..be2a696f7c3 100644 --- a/jstests/core/in8.js +++ b/jstests/core/in8.js @@ -1,23 +1,18 @@ -// SERVER-2829 Test arrays matching themselves within a $in expression. +// Test $in regular expressions with overlapping index bounds. SERVER-4677 -t = db.jstests_in8; -t.drop(); +t = db.jstests_inb; +t.drop(); -t.save( {key: [1]} ); -t.save( {key: ['1']} ); -t.save( {key: [[2]]} ); +function checkResults( query ) { + assert.eq( 4, t.count( query ) ); + assert.eq( 4, t.find( query ).itcount() ); +} -function doTest() { - assert.eq( 1, t.count( {key:[1]} ) ); - assert.eq( 1, t.count( {key:{$in:[[1]]}} ) ); - assert.eq( 1, t.count( {key:{$in:[[1]],$ne:[2]}} ) ); - assert.eq( 1, t.count( {key:{$in:[['1']],$type:2}} ) ); - assert.eq( 1, t.count( {key:['1']} ) ); - assert.eq( 1, t.count( {key:{$in:[['1']]}} ) ); - assert.eq( 1, t.count( {key:[2]} ) ); - assert.eq( 1, t.count( {key:{$in:[[2]]}} ) ); -} +t.ensureIndex( {x:1} ); +t.save( {x:'aa'} ); +t.save( {x:'ab'} ); +t.save( {x:'ac'} ); +t.save( {x:'ad'} ); -doTest(); -t.ensureIndex( {key:1} ); -doTest(); +checkResults( {x:{$in:[/^a/,/^ab/]}} ); +checkResults( {x:{$in:[/^ab/,/^a/]}} ); diff --git a/jstests/core/in9.js b/jstests/core/in9.js deleted file mode 100644 index cbe28e2e2df..00000000000 --- a/jstests/core/in9.js +++ /dev/null @@ -1,35 +0,0 @@ -// SERVER-2343 Test $in empty array matching. - -t = db.jstests_in9; -t.drop(); - -function someData() { - t.remove({}); - t.save( {key: []} ); -} - -function moreData() { - someData(); - t.save( {key: [1]} ); - t.save( {key: ['1']} ); - t.save( {key: null} ); - t.save( {} ); -} - -function check() { - assert.eq( 1, t.count( {key:[]} ) ); - assert.eq( 1, t.count( {key:{$in:[[]]}} ) ); -} - -function doTest() { - someData(); - check(); - moreData(); - check(); -} - -doTest(); - -// SERVER-1943 not fixed yet -t.ensureIndex( {key:1} ); -doTest(); diff --git a/jstests/core/inb.js b/jstests/core/inb.js deleted file mode 100644 index 34ec843d36c..00000000000 --- a/jstests/core/inb.js +++ /dev/null @@ -1,19 +0,0 @@ -// Test $in regular expressions with overlapping index bounds. SERVER-4677 - -t = db.jstests_inb; -t.drop(); - -function checkBoundsAndResults( query ) { - assert.eq( [ 'a', 'b' ], t.find( query ).explain().indexBounds.x[0] ); - assert.eq( 4, t.count( query ) ); - assert.eq( 4, t.find( query ).itcount() ); -} - -t.ensureIndex( {x:1} ); -t.save( {x:'aa'} ); -t.save( {x:'ab'} ); -t.save( {x:'ac'} ); -t.save( {x:'ad'} ); - -checkBoundsAndResults( {x:{$in:[/^a/,/^ab/]}} ); -checkBoundsAndResults( {x:{$in:[/^ab/,/^a/]}} ); diff --git a/jstests/core/index7.js b/jstests/core/index7.js index 9e3a6c66d11..bd7c75b8b08 100644 --- a/jstests/core/index7.js +++ b/jstests/core/index7.js @@ -1,67 +1,15 @@ -// index7.js Test that we use an index when and only when we expect to. +// Check that v0 keys are generated for v0 indexes SERVER-3375 -function index( q ) { - assert( q.explain().cursor.match( /^BtreeCursor/ ) , "index assert" ); -} +t = db.jstests_indexw; +t.drop(); -function noIndex( q ) { - assert( q.explain().cursor.match( /^BasicCursor/ ) , "noIndex assert" ); -} +t.save( {a:[]} ); +assert.eq( 1, t.count( {a:[]} ) ); +t.ensureIndex( {a:1} ); +assert.eq( 1, t.count( {a:[]} ) ); +t.dropIndexes(); -function start( k, q, rev) { - var exp = q.explain().indexBounds; - var s = {a:exp.a[rev?1:0][0],b:exp.b[0][0]}; - assert.eq( k.a, s.a ); - assert.eq( k.b, s.b ); -} -function end( k, q, rev) { - var exp = q.explain().indexBounds - var e = {a:exp.a[rev?1:0][1],b:exp.b[0][1]}; - assert.eq( k.a, e.a ); - assert.eq( k.b, e.b ); -} -function both( k, q ) { - start( k, q ); - end( k, q ); -} - -f = db.ed_db_index7; -f.drop(); - -f.save( { a : 5 } ) -f.ensureIndex( { a: 1 } ); -index( f.find( { a: 5 } ).sort( { a: 1 } ).hint( { a: 1 } ) ); -noIndex( f.find( { a: 5 } ).sort( { a: 1 } ).hint( { $natural: 1 } ) ); -f.drop(); - -f.ensureIndex( { a: 1, b: 1 } ); -assert.eq( 1, f.find( { a: 1 } ).hint( { a: 1, b: 1 } ).explain().indexBounds.a[0][0] ); -assert.eq( 1, f.find( { a: 1 } ).hint( { a: 1, b: 1 } ).explain().indexBounds.a[0][1] ); -assert.eq( 1, f.find( { a: 1, c: 1 } ).hint( { a: 1, b: 1 } ).explain().indexBounds.a[0][0] ); -assert.eq( 1, f.find( { a: 1, c: 1 } ).hint( { a: 1, b: 1 } ).explain().indexBounds.a[0][1] ); -assert.eq( null, f.find( { a: 1, c: 1 } ).hint( { a: 1, b: 1 } ).explain().indexBounds.c ); -assert.eq( null, f.find( { a: 1, c: 1 } ).hint( { a: 1, b: 1 } ).explain().indexBounds.c ); - -start( { a: "a", b: 1 }, f.find( { a: /^a/, b: 1 } ).hint( { a: 1, b: 1 } ) ); -start( { a: "a", b: 1 }, f.find( { a: /^a/, b: 1 } ).sort( { a: 1, b: 1 } ).hint( { a: 1, b: 1 } ) ); -start( { a: "b", b: 1 }, f.find( { a: /^a/, b: 1 } ).sort( { a: -1, b: -1 } ).hint( { a: 1, b: 1 } ), true ); -start( { a: "a", b: 1 }, f.find( { b: 1, a: /^a/ } ).hint( { a: 1, b: 1 } ) ); -end( { a: "b", b: 1 }, f.find( { a: /^a/, b: 1 } ).hint( { a: 1, b: 1 } ) ); -end( { a: "b", b: 1 }, f.find( { a: /^a/, b: 1 } ).sort( { a: 1, b: 1 } ).hint( { a: 1, b: 1 } ) ); -end( { a: "a", b: 1 }, f.find( { a: /^a/, b: 1 } ).sort( { a: -1, b: -1 } ).hint( { a: 1, b: 1 } ), true ); -end( { a: "b", b: 1 }, f.find( { b: 1, a: /^a/ } ).hint( { a: 1, b: 1 } ) ); - -start( { a: "z", b: 1 }, f.find( { a: /^z/, b: 1 } ).hint( { a: 1, b: 1 } ) ); -end( { a: "{", b: 1 }, f.find( { a: /^z/, b: 1 } ).hint( { a: 1, b: 1 } ) ); - -start( { a: "az", b: 1 }, f.find( { a: /^az/, b: 1 } ).hint( { a: 1, b: 1 } ) ); -end( { a: "a{", b: 1 }, f.find( { a: /^az/, b: 1 } ).hint( { a: 1, b: 1 } ) ); - -both( { a: 1, b: 3 }, f.find( { a: 1, b: 3 } ).hint( { a: 1, b: 1 } ) ); - -both( { a: 1, b: 2 }, f.find( { a: { $gte: 1, $lte: 1 }, b: 2 } ).hint( { a: 1, b: 1 } ) ); -both( { a: 1, b: 2 }, f.find( { a: { $gte: 1, $lte: 1 }, b: 2 } ).sort( { a: 1, b: 1 } ).hint( { a: 1, b: 1 } ) ); - -f.drop(); -f.ensureIndex( { b: 1, a: 1 } ); -both( { a: 1, b: 3 }, f.find( { a: 1, b: 3 } ).hint( { b: 1, a: 1 } ) ); +// The count result is incorrect - just checking here that v0 key generation is used. +t.ensureIndex( {a:1}, {v:0} ); +// QUERY_MIGRATION: WE GET THIS RIGHT...BY CHANCE? +// assert.eq( 0, t.count( {a:[]} ) ); diff --git a/jstests/core/indexOtherNamespace.js b/jstests/core/indexOtherNamespace.js index f71e6d36558..9876fb841f9 100644 --- a/jstests/core/indexOtherNamespace.js +++ b/jstests/core/indexOtherNamespace.js @@ -1,16 +1,19 @@ // SERVER-8814: Test that only the system.indexes namespace can be used to build indexes. +// Include helpers for analyzing explain output. +load("jstests/libs/analyze_plan.js"); + var otherDB = db.getSiblingDB("indexOtherNS"); otherDB.dropDatabase(); otherDB.foo.insert({a:1}) assert.eq(1, otherDB.foo.getIndexes().length); -assert.eq("BasicCursor", otherDB.foo.find({a:1}).explain().cursor); +assert(isCollscan(otherDB.foo.find({a:1}).explain().queryPlanner.winningPlan)); assert.writeError(otherDB.randomNS.system.indexes.insert({ ns: "indexOtherNS.foo", key: { a: 1 }, name: "a_1"})); // Assert that index didn't actually get built assert.eq(1, otherDB.foo.getIndexes().length); -assert.eq("BasicCursor", otherDB.foo.find({a:1}).explain().cursor); +assert(isCollscan(otherDB.foo.find({a:1}).explain().queryPlanner.winningPlan)); otherDB.dropDatabase(); diff --git a/jstests/core/index_check2.js b/jstests/core/index_check2.js index eed3b8e42b7..9eade5a68fa 100644 --- a/jstests/core/index_check2.js +++ b/jstests/core/index_check2.js @@ -2,6 +2,9 @@ t = db.index_check2; t.drop(); +// Include helpers for analyzing explain output. +load("jstests/libs/analyze_plan.js"); + for ( var i=0; i<1000; i++ ){ var a = []; for ( var j=1; j<5; j++ ){ @@ -24,18 +27,16 @@ assert.eq( 120 , t.find( q1 ).itcount() , "q1 a"); assert.eq( 120 , t.find( q2 ).itcount() , "q2 a" ); assert.eq( 60 , t.find( q3 ).itcount() , "q3 a"); -assert.eq( "BtreeCursor tags_1" , t.find( q1 ).explain().cursor , "e1" ); -assert.eq( "BtreeCursor tags_1" , t.find( q2 ).explain().cursor , "e2" ); -assert.eq( "BtreeCursor tags_1" , t.find( q3 ).explain().cursor , "e3" ); +// We expect these queries to use index scans over { tags: 1 }. +assert( isIxscan(t.find(q1).explain().queryPlanner.winningPlan) , "e1" ); +assert( isIxscan(t.find(q2).explain().queryPlanner.winningPlan) , "e2" ); +assert( isIxscan(t.find(q3).explain().queryPlanner.winningPlan) , "e3" ); -scanned1 = t.find(q1).explain().nscanned; -scanned2 = t.find(q2).explain().nscanned; -scanned3 = t.find(q3).explain().nscanned; +scanned1 = t.find(q1).explain().executionStats.totalKeysExamined; +scanned2 = t.find(q2).explain().executionStats.totalKeysExamined; +scanned3 = t.find(q3).explain().executionStats.totalKeysExamined; //print( "scanned1: " + scanned1 + " scanned2: " + scanned2 + " scanned3: " + scanned3 ); // $all should just iterate either of the words assert( scanned3 <= Math.max( scanned1 , scanned2 ) , "$all makes query optimizer not work well" ); - -exp3 = t.find( q3 ).explain(); -assert.eq( exp3.indexBounds.tags[0][0], exp3.indexBounds.tags[0][1], "$all range not a single key" ); diff --git a/jstests/core/index_check3.js b/jstests/core/index_check3.js index 55515aff3f5..bef79fd650d 100644 --- a/jstests/core/index_check3.js +++ b/jstests/core/index_check3.js @@ -29,10 +29,10 @@ for ( var i=0; i<100; i++ ){ t.ensureIndex( { foo : 1 } ); -//printjson( t.find( { foo : { $lt : 50 } } ).explain() ); -assert.gt( 30 , t.find( { foo : { $lt : 50 } } ).explain().nscanned , "lt" ); -//printjson( t.find( { foo : { $gt : 50 } } ).explain() ); -assert.gt( 30 , t.find( { foo : { $gt : 50 } } ).explain().nscanned , "gt" ); +var explain = t.find( { foo : { $lt : 50 } } ).explain(); +assert.gt( 30 , explain.executionStats.totalKeysExamined , "lt" ); +var explain = t.find( { foo : { $gt : 50 } } ).explain(); +assert.gt( 30 , explain.executionStats.totalKeysExamined , "gt" ); t.drop(); @@ -43,11 +43,12 @@ for( var i=0; i < 10; ++i ) { t.ensureIndex( { i : 1 } ); -//printjson( t.find( { i : { $lte : 'a' } } ).explain() ); -assert.gt( 3 , t.find( { i : { $lte : 'a' } } ).explain().nscanned , "lte" ); +var explain = t.find( { i : { $lte : 'a' } } ).explain(); +assert.gt( 3 , explain.executionStats.totalKeysExamined , "lte" ); //printjson( t.find( { i : { $gte : 'a' } } ).explain() ); // bug SERVER-99 -assert.gt( 3 , t.find( { i : { $gte : 'a' } } ).explain().nscanned , "gte" ); +var explain = t.find( { i : { $gte : 'a' } } ).explain(); +assert.gt( 3 , explain.executionStats.totalKeysExamined , "gte" ); assert.eq( 1 , t.find( { i : { $gte : 'a' } } ).count() , "gte a" ); assert.eq( 1 , t.find( { i : { $gte : 'a' } } ).itcount() , "gte b" ); assert.eq( 1 , t.find( { i : { $gte : 'a' } } ).sort( { i : 1 } ).count() , "gte c" ); @@ -55,7 +56,8 @@ assert.eq( 1 , t.find( { i : { $gte : 'a' } } ).sort( { i : 1 } ).itcount() , "g t.save( { i : "b" } ); -assert.gt( 3 , t.find( { i : { $gte : 'a' } } ).explain().nscanned , "gte" ); +var explain = t.find( { i : { $gte : 'a' } } ).explain(); +assert.gt( 3 , explain.executionStats.totalKeysExamined , "gte" ); assert.eq( 2 , t.find( { i : { $gte : 'a' } } ).count() , "gte a2" ); assert.eq( 2 , t.find( { i : { $gte : 'a' } } ).itcount() , "gte b2" ); assert.eq( 2 , t.find( { i : { $gte : 'a' , $lt : MaxKey } } ).itcount() , "gte c2" ); diff --git a/jstests/core/index_check6.js b/jstests/core/index_check6.js index be395fb3d2e..090fd27d4c3 100644 --- a/jstests/core/index_check6.js +++ b/jstests/core/index_check6.js @@ -2,6 +2,11 @@ t = db.index_check6; t.drop(); +function keysExamined(query, hint) { + var explain = t.find(query).hint(hint).explain(); + return explain.executionStats.totalKeysExamined; +} + t.ensureIndex( { age : 1 , rating : 1 } ); for ( var age=10; age<50; age++ ){ @@ -10,16 +15,22 @@ for ( var age=10; age<50; age++ ){ } } -assert.eq( 10 , t.find( { age : 30 } ).explain().nscanned , "A" ); -assert.eq( 20 , t.find( { age : { $gte : 29 , $lte : 30 } } ).explain().nscanned , "B" ); -assert.eq( 18 , t.find( { age : { $gte : 25 , $lte : 30 }, rating: {$in: [0,9] } } ).hint( {age:1,rating:1} ).explain().nscanned , "C1" ); -assert.eq( 23 , t.find( { age : { $gte : 25 , $lte : 30 }, rating: {$in: [0,8] } } ).hint( {age:1,rating:1} ).explain().nscanned , "C2" ); -assert.eq( 28 , t.find( { age : { $gte : 25 , $lte : 30 }, rating: {$in: [1,8] } } ).hint( {age:1,rating:1} ).explain().nscanned , "C3" ); +assert.eq( 10 , keysExamined( { age : 30 }, {} ) , "A" ); +assert.eq( 20 , keysExamined( { age : { $gte : 29 , $lte : 30 } }, {} ) , "B" ); +assert.eq( 18 , keysExamined( { age : { $gte : 25 , $lte : 30 }, rating: {$in: [0,9] } }, + {age:1,rating:1} ) , "C1" ); +assert.eq( 23 , keysExamined( { age : { $gte : 25 , $lte : 30 }, rating: {$in: [0,8] } }, + {age:1,rating:1} ) , "C2" ); +assert.eq( 28 , keysExamined( { age : { $gte : 25 , $lte : 30 }, rating: {$in: [1,8] } }, + {age:1,rating:1} ) , "C3" ); -assert.eq( 4 , t.find( { age : { $gte : 29 , $lte : 30 } , rating : 5 } ).hint( {age:1,rating:1} ).explain().nscanned , "C" ); // SERVER-371 -assert.eq( 6 , t.find( { age : { $gte : 29 , $lte : 30 } , rating : { $gte : 4 , $lte : 5 } } ).hint( {age:1,rating:1} ).explain().nscanned , "D" ); // SERVER-371 +assert.eq( 4 , keysExamined( { age : { $gte : 29 , $lte : 30 } , rating : 5 }, + {age:1,rating:1} ) , "C" ); // SERVER-371 +assert.eq( 6 , keysExamined( { age : { $gte : 29 , $lte : 30 } , rating : { $gte : 4 , $lte : 5 } }, + {age:1,rating:1} ) , "D" ); // SERVER-371 -assert.eq.automsg( "2", "t.find( { age:30, rating:{ $gte:4, $lte:5} } ).explain().nscanned" ); +assert.eq.automsg( "2", "t.find( { age:30, rating:{ $gte:4, $lte:5} } ).explain()" + + ".executionStats.totalKeysExamined" ); t.drop(); @@ -32,7 +43,8 @@ for ( var a=1; a<10; a++ ){ } function doQuery( count, query, sort, index ) { - var nscanned = t.find( query ).hint( index ).sort( sort ).explain().nscanned; + var explain = t.find( query ).hint( index ).sort( sort ).explain(); + var nscanned = explain.executionStats.totalKeysExamined; assert(Math.abs(count - nscanned) <= 2); } diff --git a/jstests/core/index_check7.js b/jstests/core/index_check7.js index 1d0aaebba35..c23ef4eda1e 100644 --- a/jstests/core/index_check7.js +++ b/jstests/core/index_check7.js @@ -6,10 +6,10 @@ for ( var i=0; i<100; i++ ) t.save( { x : i } ) t.ensureIndex( { x : 1 } ) -assert.eq( 1 , t.find( { x : 27 } ).explain().nscanned , "A" ) +assert.eq( 1 , t.find( { x : 27 } ).explain().executionStats.totalKeysExamined , "A" ) t.ensureIndex( { x : -1 } ) -assert.eq( 1 , t.find( { x : 27 } ).explain().nscanned , "B" ) +assert.eq( 1 , t.find( { x : 27 } ).explain().executionStats.totalKeysExamined , "B" ) -assert.eq( 40 , t.find( { x : { $gt : 59 } } ).explain().nscanned , "C" ); +assert.eq( 40 , t.find( { x : { $gt : 59 } } ).explain().executionStats.totalKeysExamined , "C" ); diff --git a/jstests/core/index_check8.js b/jstests/core/index_check8.js deleted file mode 100644 index 1964ecbe7fc..00000000000 --- a/jstests/core/index_check8.js +++ /dev/null @@ -1,21 +0,0 @@ - -t = db.index_check8 -t.drop(); - -t.insert( { a : 1 , b : 1 , c : 1 , d : 1 , e : 1 } ) -t.ensureIndex( { a : 1 , b : 1 , c : 1 } ) -t.ensureIndex({ a: 1, b: 1, d: 1, e: 1 }) - -// this block could be added to many tests in theory... -if ((new Date()) % 10 == 0) { - var coll = t.toString().substring(db.toString().length + 1); - print("compacting " + coll + " before continuing testing"); - // don't check return code - false for mongos - print("ok: " + db.runCommand({ compact: coll, dev: true })); -} - -x = t.find( { a : 1 , b : 1 , d : 1 } ).sort( { e : 1 } ).explain() -assert( ! x.scanAndOrder , "A : " + tojson( x ) ) - -x = t.find( { a : 1 , b : 1 , c : 1 , d : 1 } ).sort( { e : 1 } ).explain() -//assert( ! x.scanAndOrder , "B : " + tojson( x ) ) diff --git a/jstests/core/index_elemmatch1.js b/jstests/core/index_elemmatch1.js index 263eb252364..99418e83839 100644 --- a/jstests/core/index_elemmatch1.js +++ b/jstests/core/index_elemmatch1.js @@ -34,8 +34,8 @@ function nscannedForCursor( explain, cursor ) { return -1; } -assert.eq( t.find(q).itcount(), - nscannedForCursor( t.find(q).explain(true), 'BtreeCursor arr.x_1_a_1' ), "A5" ); +var explain = t.find(q).hint( { "arr.x" : 1 , a : 1 } ).explain(); +assert.eq( t.find(q).itcount(), explain.executionStats.totalKeysExamined ); printjson(t.find(q).explain()); print("Num results:"); diff --git a/jstests/core/index_many.js b/jstests/core/index_many.js index 70f39c4719c..a9eddbb32f1 100644 --- a/jstests/core/index_many.js +++ b/jstests/core/index_many.js @@ -34,10 +34,8 @@ function f() { assert(lim == 64, "not 64 indexes"); assert(t.find({ x: 9 }).length() == 1, "b"); - assert(t.find({ x: 9 }).explain().cursor.match(/Btree/), "not using index?"); assert(t.find({ y: 99 }).length() == 2, "y idx"); - assert(t.find({ y: 99 }).explain().cursor.match(/Btree/), "not using y index?"); /* check that renamecollection remaps all the indexes right */ assert(t.renameCollection("many2").ok, "rename failed"); diff --git a/jstests/core/indexj.js b/jstests/core/indexj.js index 6d8ac85c972..e58104d75c6 100644 --- a/jstests/core/indexj.js +++ b/jstests/core/indexj.js @@ -3,23 +3,34 @@ t = db.jstests_indexj; t.drop(); +function keysExamined(query, hint, sort) { + if (!hint) { + hint = {}; + } + if (!sort) { + sort = {}; + } + var explain = t.find(query).sort(sort).hint(hint).explain(); + return explain.executionStats.totalKeysExamined; +} + t.ensureIndex( {a:1} ); t.save( {a:5} ); -assert.eq( 0, t.find( { a: { $gt:4, $lt:5 } } ).explain().nscanned, "A" ); +assert.eq( 0, keysExamined( { a: { $gt:4, $lt:5 } } ), "A" ); t.drop(); t.ensureIndex( {a:1} ); t.save( {a:4} ); -assert.eq( 0, t.find( { a: { $gt:4, $lt:5 } } ).explain().nscanned, "B" ); +assert.eq( 0, keysExamined( { a: { $gt:4, $lt:5 } } ), "B" ); t.save( {a:5} ); -assert.eq( 0, t.find( { a: { $gt:4, $lt:5 } } ).explain().nscanned, "D" ); +assert.eq( 0, keysExamined( { a: { $gt:4, $lt:5 } } ), "D" ); t.save( {a:4} ); -assert.eq( 0, t.find( { a: { $gt:4, $lt:5 } } ).explain().nscanned, "C" ); +assert.eq( 0, keysExamined( { a: { $gt:4, $lt:5 } } ), "C" ); t.save( {a:5} ); -assert.eq( 0, t.find( { a: { $gt:4, $lt:5 } } ).explain().nscanned, "D" ); +assert.eq( 0, keysExamined( { a: { $gt:4, $lt:5 } } ), "D" ); t.drop(); t.ensureIndex( {a:1,b:1} ); @@ -28,17 +39,17 @@ t.save( { a:1,b:2 } ); t.save( { a:2,b:1 } ); t.save( { a:2,b:2 } ); -assert.eq( 2, t.find( { a:{$in:[1,2]}, b:{$gt:1,$lt:2} } ).hint( {a:1,b:1} ).explain().nscanned ); -assert.eq( 2, t.find( { a:{$in:[1,2]}, b:{$gt:1,$lt:2} } ).hint( {a:1,b:1} ).sort( {a:-1,b:-1} ).explain().nscanned ); +assert.eq( 2, keysExamined( { a:{$in:[1,2]}, b:{$gt:1,$lt:2} }, {a:1,b:1} ) ); +assert.eq( 2, keysExamined( { a:{$in:[1,2]}, b:{$gt:1,$lt:2} }, {a:1,b:1}, {a:-1,b:-1} ) ); t.save( {a:1,b:1} ); t.save( {a:1,b:1} ); -assert.eq( 2, t.find( { a:{$in:[1,2]}, b:{$gt:1,$lt:2} } ).hint( {a:1,b:1} ).explain().nscanned ); -assert.eq( 2, t.find( { a:{$in:[1,2]}, b:{$gt:1,$lt:2} } ).hint( {a:1,b:1} ).explain().nscanned ); -assert.eq( 2, t.find( { a:{$in:[1,2]}, b:{$gt:1,$lt:2} } ).hint( {a:1,b:1} ).sort( {a:-1,b:-1} ).explain().nscanned ); +assert.eq( 2, keysExamined( { a:{$in:[1,2]}, b:{$gt:1,$lt:2} }, {a:1,b:1} ) ); +assert.eq( 2, keysExamined( { a:{$in:[1,2]}, b:{$gt:1,$lt:2} }, {a:1,b:1} ) ); +assert.eq( 2, keysExamined( { a:{$in:[1,2]}, b:{$gt:1,$lt:2} }, {a:1,b:1}, {a:-1,b:-1} ) ); -assert.eq( 1, t.find( { a:{$in:[1,1.9]}, b:{$gt:1,$lt:2} } ).hint( {a:1,b:1} ).explain().nscanned ); -assert.eq( 1, t.find( { a:{$in:[1.1,2]}, b:{$gt:1,$lt:2} } ).hint( {a:1,b:1} ).sort( {a:-1,b:-1} ).explain().nscanned ); +assert.eq( 1, keysExamined( { a:{$in:[1,1.9]}, b:{$gt:1,$lt:2} }, {a:1,b:1} ) ); +assert.eq( 1, keysExamined( { a:{$in:[1.1,2]}, b:{$gt:1,$lt:2} }, {a:1,b:1}, {a:-1,b:-1} ) ); t.save( { a:1,b:1.5} ); -assert.eq( 3, t.find( { a:{$in:[1,2]}, b:{$gt:1,$lt:2} } ).hint( {a:1,b:1} ).explain().nscanned, "F" ); +assert.eq( 3, keysExamined( { a:{$in:[1,2]}, b:{$gt:1,$lt:2} }, {a:1,b:1} ), "F" ); diff --git a/jstests/core/indexm.js b/jstests/core/indexm.js index 6b31ea628cd..045c3bd2053 100644 --- a/jstests/core/indexm.js +++ b/jstests/core/indexm.js @@ -35,4 +35,4 @@ test(); // Drop the indexes. t.dropIndexes(); -test();
\ No newline at end of file +test(); diff --git a/jstests/core/indexn.js b/jstests/core/indexn.js index 9abb001eed9..e868583257e 100644 --- a/jstests/core/indexn.js +++ b/jstests/core/indexn.js @@ -4,11 +4,6 @@ t = db.jstests_indexn; t.drop(); -function checkImpossibleMatch( explain ) { - printjson(explain); - assert.eq( 0, explain.n ); -} - t.save( {a:1,b:[1,2]} ); t.ensureIndex( {a:1} ); @@ -16,34 +11,19 @@ t.ensureIndex( {b:1} ); // {a:1} is a single key index, so no matches are possible for this query assert.eq( 0, t.count( {a:{$gt:5,$lt:0}} ) ); -checkImpossibleMatch( t.find( {a:{$gt:5,$lt:0}} ).explain() ); assert.eq( 0, t.count( {a:{$gt:5,$lt:0},b:2} ) ); -checkImpossibleMatch( t.find( {a:{$gt:5,$lt:0},b:2} ).explain() ); assert.eq( 0, t.count( {a:{$gt:5,$lt:0},b:{$gt:0,$lt:5}} ) ); -checkImpossibleMatch( t.find( {a:{$gt:5,$lt:0},b:{$gt:0,$lt:5}} ).explain() ); // One clause of an $or is an "impossible match" printjson( t.find( {$or:[{a:{$gt:5,$lt:0}},{a:1}]} ).explain() ) assert.eq( 1, t.count( {$or:[{a:{$gt:5,$lt:0}},{a:1}]} ) ); -checkImpossibleMatch( t.find( {$or:[{a:{$gt:5,$lt:0}},{a:1}]} ).explain().clauses[ 0 ] ); // One clause of an $or is an "impossible match"; original order of the $or // does not matter. printjson( t.find( {$or:[{a:1},{a:{$gt:5,$lt:0}}]} ).explain() ) assert.eq( 1, t.count( {$or:[{a:1},{a:{$gt:5,$lt:0}}]} ) ); -checkImpossibleMatch( t.find( {$or:[{a:1},{a:{$gt:5,$lt:0}}]} ).explain().clauses[ 0 ] ); t.save( {a:2} ); - -// Descriptive test: query system sees this query as an $or where -// one clause of the $or is an $and. The $and bounds get intersected -// forming a clause with empty index bounds. The union of the $or bounds -// produces the two point intervals [1, 1] and [2, 2]. assert.eq( 2, t.count( {$or:[{a:1},{a:{$gt:5,$lt:0}},{a:2}]} ) ); -explain = t.find( {$or:[{a:1},{a:{$gt:5,$lt:0}},{a:2}]} ).explain(); -printjson( explain ) -assert.eq( 2, explain.clauses.length ); -checkImpossibleMatch( explain.clauses[ 0 ] ); -assert.eq( [[1, 1], [2,2]], explain.clauses[ 1 ].indexBounds.a ); diff --git a/jstests/core/indexq.js b/jstests/core/indexq.js deleted file mode 100644 index 38cd27b8798..00000000000 --- a/jstests/core/indexq.js +++ /dev/null @@ -1,20 +0,0 @@ -// Test multikey range preference for a fully included range SERVER-958. - -t = db.jstests_indexq; -t.drop(); - -t.ensureIndex( {a:1} ); -// Single key index -assert.eq( 5, t.find( {a:{$gt:4,$gte:5}} ).explain().indexBounds.a[ 0 ][ 0 ] ); -assert.eq( [[1,1],[2,2]], t.find( {a:{$in:[1,2,3]},$or:[{a:{$in:[1,2]}}]} ).explain().indexBounds.a ); - -t.save( {a:[1,3]} ); -// Now with multi key index. - -// SERVER-12281: We should know that >4 is worse than >5 -// assert.eq( 5, t.find( {a:{$gt:4,$gte:5}} ).explain().indexBounds.a[ 0 ][ 0 ] ); - -printjson(t.find( {a:{$in:[1,2,3]},$or:[{a:{$in:[1,2]}}]} ).explain()) - -// SERVER-12281: We should know that in[1,2] is better than in[1,2,3]. -// assert.eq( [[1,1],[2,2]], t.find( {a:{$in:[1,2,3]},$or:[{a:{$in:[1,2]}}]} ).explain().indexBounds.a ); diff --git a/jstests/core/indexr.js b/jstests/core/indexr.js index c3eecd045c8..1f7b75bbcf7 100644 --- a/jstests/core/indexr.js +++ b/jstests/core/indexr.js @@ -14,14 +14,10 @@ t.ensureIndex( {'a.b':1,'a.c':1} ); t.ensureIndex( {a:1,'a.c':1} ); assert.eq( 0, t.count( { 'a.b':{ $gt:2 }, 'a.c': { $lt:4 } } ) ); assert.eq( 0, t.count( { a:{ b:3, c:6 }, 'a.c': { $lt:4 } } ) ); -assert.eq( 4, t.find( { 'a.b':{ $gt:2 }, 'a.c': { $lt:4 } } ).explain().indexBounds['a.c'][0][1] ); -assert.eq( 4, t.find( { a:{ b:3, c:6 }, 'a.c': { $lt:4 } } ).explain().indexBounds['a.c'][0][1] ); t.save( { a: { b: 3, c: 3 } } ); assert.eq( 1, t.count( { 'a.b':{ $gt:2 }, 'a.c': { $lt:4 } } ) ); assert.eq( 1, t.count( { a:{ b:3, c:3 }, 'a.c': { $lt:4 } } ) ); -assert.eq( 4, t.find( { 'a.b':{ $gt:2 }, 'a.c': { $lt:4 } } ).explain().indexBounds['a.c'][0][1] ); -assert.eq( 4, t.find( { a:{ b:3, c:3 }, 'a.c': { $lt:4 } } ).explain().indexBounds['a.c'][0][1] ); // Check with multikey indexes. t.remove({}); @@ -29,16 +25,11 @@ t.save( { a: [ { b: 3, c: 6 }, { b: 1, c: 1 } ] } ); assert.eq( 1, t.count( { 'a.b':{ $gt:2 }, 'a.c': { $lt:4 } } ) ); assert.eq( 1, t.count( { a:{ b:3, c:6 }, 'a.c': { $lt:4 } } ) ); -assert.eq( [[{$minElement:1},{$maxElement:1}]], t.find( { 'a.b':{ $gt:2 }, 'a.c': { $lt:4 } } ).explain().indexBounds['a.c'] ); -assert.eq( [[{$minElement:1},{$maxElement:1}]], t.find( { a:{ b:3, c:6 }, 'a.c': { $lt:4 } } ).explain().indexBounds['a.c'] ); // Check reverse direction. assert.eq( 1, t.find( { 'a.b':{ $gt:2 }, 'a.c': { $lt:4 } } ).sort( {'a.b':-1} ).itcount() ); assert.eq( 1, t.find( { a:{ b:3, c:6 }, 'a.c': { $lt:4 } } ).sort( {a:-1} ).itcount() ); -assert.eq( [[{$maxElement:1},{$minElement:1}]], t.find( { 'a.b':{ $gt:2 }, 'a.c': { $lt:4 } } ).sort( {'a.b':-1} ).explain().indexBounds['a.c'] ); -assert.eq( [[{$maxElement:1},{$minElement:1}]], t.find( { a:{ b:3, c:6 }, 'a.c': { $lt:4 } } ).sort( {a:-1} ).explain().indexBounds['a.c'] ); - // Check second field is constrained if first is not. assert.eq( 1, t.find( { 'a.c': { $lt:4 } } ).hint( {'a.b':1,'a.c':1} ).itcount() ); assert.eq( 1, t.find( { 'a.c': { $lt:4 } } ).hint( {a:1,'a.c':1} ).itcount() ); diff --git a/jstests/core/indexs.js b/jstests/core/indexs.js index 609f912affe..0b7bfe412c4 100644 --- a/jstests/core/indexs.js +++ b/jstests/core/indexs.js @@ -11,11 +11,8 @@ t.drop(); t.ensureIndex( {a:1,'a.b':1} ); t.save( { a: { b: 3 } } ); assert.eq( 1, t.count( { a:{ b:3 } } ) ); -ib = t.find( { a:{ b:3 } } ).explain().indexBounds; t.drop(); t.ensureIndex( {a:1,'a.b':1} ); t.save( { a: [ { b: 3 } ] } ); -assert.eq( ib, t.find( { a:{ b:3 } } ).explain().indexBounds ); -assert.eq( 1, t.find( { a:{ b:3 } } ).explain().nscanned ); assert.eq( 1, t.count( { a:{ b:3 } } ) ); diff --git a/jstests/core/indext.js b/jstests/core/indext.js index e418dc2e959..134e81acdeb 100644 --- a/jstests/core/indext.js +++ b/jstests/core/indext.js @@ -7,15 +7,12 @@ t.ensureIndex( {'a.b':1}, {sparse:true} ); t.save( {a:[]} ); t.save( {a:1} ); assert.eq( 0, t.find().hint( {'a.b':1} ).itcount() ); -assert.eq( 0, t.find().hint( {'a.b':1} ).explain().nscanned ); t.ensureIndex( {'a.b':1,'a.c':1}, {sparse:true} ); t.save( {a:[]} ); t.save( {a:1} ); assert.eq( 0, t.find().hint( {'a.b':1,'a.c':1} ).itcount() ); -assert.eq( 0, t.find().hint( {'a.b':1,'a.c':1} ).explain().nscanned ); t.save( {a:[{b:1}]} ); t.save( {a:1} ); assert.eq( 1, t.find().hint( {'a.b':1,'a.c':1} ).itcount() ); -assert.eq( 1, t.find().hint( {'a.b':1,'a.c':1} ).explain().nscanned ); diff --git a/jstests/core/indexv.js b/jstests/core/indexv.js index 334ec432d74..a30541de36c 100644 --- a/jstests/core/indexv.js +++ b/jstests/core/indexv.js @@ -7,12 +7,12 @@ t.ensureIndex( {'a.b':1} ); t.save( {a:[{},{b:1}]} ); var e = t.find( {'a.b':null} ).explain(); -assert.eq( 1, e.n ); -assert.eq( 1, e.nscanned ); +assert.eq( 1, e.executionStats.nReturned ); +assert.eq( 1, e.executionStats.totalKeysExamined ); t.drop(); t.ensureIndex( {'a.b.c':1} ); t.save( {a:[{b:[]},{b:{c:1}}]} ); var e = t.find( {'a.b.c':null} ).explain(); -assert.eq( 0, e.n ); -assert.eq( 1, e.nscanned ); +assert.eq( 0, e.executionStats.nReturned ); +assert.eq( 1, e.executionStats.totalKeysExamined ); diff --git a/jstests/core/indexw.js b/jstests/core/indexw.js deleted file mode 100644 index bd7c75b8b08..00000000000 --- a/jstests/core/indexw.js +++ /dev/null @@ -1,15 +0,0 @@ -// Check that v0 keys are generated for v0 indexes SERVER-3375 - -t = db.jstests_indexw; -t.drop(); - -t.save( {a:[]} ); -assert.eq( 1, t.count( {a:[]} ) ); -t.ensureIndex( {a:1} ); -assert.eq( 1, t.count( {a:[]} ) ); -t.dropIndexes(); - -// The count result is incorrect - just checking here that v0 key generation is used. -t.ensureIndex( {a:1}, {v:0} ); -// QUERY_MIGRATION: WE GET THIS RIGHT...BY CHANCE? -// assert.eq( 0, t.count( {a:[]} ) ); diff --git a/jstests/core/mod1.js b/jstests/core/mod1.js index 46e3482bc72..d578190737f 100644 --- a/jstests/core/mod1.js +++ b/jstests/core/mod1.js @@ -11,7 +11,8 @@ t.save( { a : "adasdas" } ); assert.eq( 2 , t.find( "this.a % 10 == 1" ).itcount() , "A1" ); assert.eq( 2 , t.find( { a : { $mod : [ 10 , 1 ] } } ).itcount() , "A2" ); -assert.eq( 6 , t.find( { a : { $mod : [ 10 , 1 ] } } ).explain().nscanned , "A3" ); +assert.eq( 0 , t.find( { a : { $mod : [ 10 , 1 ] } } ).explain() + .executionStats.totalKeysExamined , "A3" ); t.ensureIndex( { a : 1 } ); @@ -20,6 +21,7 @@ assert.eq( 2 , t.find( { a : { $mod : [ 10 , 1 ] } } ).itcount() , "B2" ); assert.eq( 1 , t.find( "this.a % 10 == 0" ).itcount() , "B3" ); assert.eq( 1 , t.find( { a : { $mod : [ 10 , 0 ] } } ).itcount() , "B4" ); -assert.eq( 4 , t.find( { a : { $mod : [ 10 , 1 ] } } ).explain().nscanned , "B5" ); +assert.eq( 4 , t.find( { a : { $mod : [ 10 , 1 ] } } ).explain() + .executionStats.totalKeysExamined, "B5" ); -assert.eq( 1, t.find( { a: { $gt: 5, $mod : [ 10, 1 ] } } ).itcount() );
\ No newline at end of file +assert.eq( 1, t.find( { a: { $gt: 5, $mod : [ 10, 1 ] } } ).itcount() ); diff --git a/jstests/core/mr_index.js b/jstests/core/mr_index.js index 521d44d29f0..394ecc3f650 100644 --- a/jstests/core/mr_index.js +++ b/jstests/core/mr_index.js @@ -28,16 +28,12 @@ ex = function(){ } res = t.mapReduce( m , r , { out : outName } ) - -assert.eq( "BasicCursor" , ex().cursor , "A1" ) + +assert.eq( 3 , ex().executionStats.nReturned , "A1" ) out.ensureIndex( { value : 1 } ) -assert.eq( "BtreeCursor value_1" , ex().cursor , "A2" ) -assert.eq( 3 , ex().n , "A3" ) +assert.eq( 3 , ex().executionStats.nReturned , "A2" ) res = t.mapReduce( m , r , { out : outName } ) - -assert.eq( "BtreeCursor value_1" , ex().cursor , "B1" ) -assert.eq( 3 , ex().n , "B2" ) -res.drop() - +assert.eq( 3 , ex().executionStats.nReturned , "B1" ) +res.drop() diff --git a/jstests/core/ne2.js b/jstests/core/ne2.js index a69bfd6a114..c34f482a389 100644 --- a/jstests/core/ne2.js +++ b/jstests/core/ne2.js @@ -10,7 +10,7 @@ t.save( { a:0 } ); t.save( { a:0.5 } ); e = t.find( { a: { $ne: 0 } } ).explain( true ); -assert.eq( 2, e.n, 'A' ); +assert.eq( 2, e.executionStats.nReturned, 'A' ); e = t.find( { a: { $gt: -1, $lt: 1, $ne: 0 } } ).explain(); -assert.eq( 2, e.n, 'B' ); +assert.eq( 2, e.executionStats.nReturned, 'B' ); diff --git a/jstests/core/or2.js b/jstests/core/or2.js index 00e9f68decf..f8de6c42ef9 100644 --- a/jstests/core/or2.js +++ b/jstests/core/or2.js @@ -1,6 +1,9 @@ t = db.jstests_or2; t.drop(); +// Include helpers for analyzing explain output. +load("jstests/libs/analyze_plan.js"); + checkArrs = function( a, b, m ) { assert.eq( a.length, b.length, m ); aStr = []; @@ -16,7 +19,7 @@ doTest = function( index ) { if ( index == null ) { index = true; } - + t.save( {_id:0,x:0,a:1} ); t.save( {_id:1,x:0,a:2} ); t.save( {_id:2,x:0,b:1} ); @@ -25,23 +28,25 @@ doTest = function( index ) { t.save( {_id:5,x:1,a:1,b:2} ); t.save( {_id:6,x:1,a:2,b:1} ); t.save( {_id:7,x:1,a:2,b:2} ); - + assert.throws( function() { t.find( { x:0,$or:"a" } ).toArray(); } ); assert.throws( function() { t.find( { x:0,$or:[] } ).toArray(); } ); assert.throws( function() { t.find( { x:0,$or:[ "a" ] } ).toArray(); } ); - + a1 = t.find( { x:0, $or: [ { a : 1 } ] } ).toArray(); checkArrs( [ { _id:0, x:0, a:1 } ], a1 ); if ( index ) { - assert( t.find( { x:0,$or: [ { a : 1 } ] } ).explain().cursor.match( /Btree/ ) ); + var explain = t.find( { x:0,$or: [ { a : 1 } ] } ).explain(); + assert( isIxscan(explain.queryPlanner.winningPlan) ); } - + a1b2 = t.find( { x:1, $or: [ { a : 1 }, { b : 2 } ] } ).toArray(); checkArrs( [ { _id:4, x:1, a:1, b:1 }, { _id:5, x:1, a:1, b:2 }, { _id:7, x:1, a:2, b:2 } ], a1b2 ); if ( index ) { - assert( t.find( { x:0,$or: [ { a : 1 } ] } ).explain().cursor.match( /Btree/ ) ); + var explain = t.find( { x:0,$or: [ { a : 1 } ] } ).explain(); + assert( isIxscan(explain.queryPlanner.winningPlan) ); } - + /* t.drop(); obj = {_id:0,x:10,a:[1,2,3]}; diff --git a/jstests/core/or3.js b/jstests/core/or3.js index 7759e689f84..1dab4d55ecd 100644 --- a/jstests/core/or3.js +++ b/jstests/core/or3.js @@ -1,6 +1,9 @@ t = db.jstests_or3; t.drop(); +// Include helpers for analyzing explain output. +load("jstests/libs/analyze_plan.js"); + checkArrs = function( a, b, m ) { assert.eq( a.length, b.length, m ); aStr = []; @@ -37,7 +40,8 @@ doTest = function( index ) { checkArrs( [ { _id:6, x:1, a:2, b:1 } ], an1bn2 ); checkArrs( t.find( { x:1, a:{$ne:1}, b:{$ne:2} } ).toArray(), an1bn2 ); if ( index ) { - assert( t.find( { x:1, $nor: [ { a : 1 }, { b : 2 } ] } ).explain().cursor.match( /Btree/ ) ); + var explain = t.find( { x:1, $nor: [ { a : 1 }, { b : 2 } ] } ).explain(); + assert( isIxscan(explain.queryPlanner.winningPlan) ); } an1b2 = t.find( { $nor: [ { a : 1 } ], $or: [ { b : 2 } ] } ).toArray(); diff --git a/jstests/core/or4.js b/jstests/core/or4.js index 23c10bba8e2..a47884364c3 100644 --- a/jstests/core/or4.js +++ b/jstests/core/or4.js @@ -78,8 +78,6 @@ assert.eq.automsg( "[1,2]", "Array.sort( t.distinct( 'a', {$or:[{a:2},{b:3}]} ) assert.eq.automsg( "[{a:2},{a:null},{a:1}]", "t.group( {key:{a:1}, cond:{$or:[{a:2},{b:3}]}, reduce:function( x, y ) { }, initial:{} } )" ); assert.eq.automsg( "5", "t.mapReduce( function() { emit( 'a', this.a ); }, function( key, vals ) { return vals.length; }, {out:{inline:true},query:{$or:[{a:2},{b:3}]}} ).counts.input" ); -explain = t.find( {$or:[{a:2},{b:3}]} ).explain(); - t.remove( {} ); t.save( {a:[1,2]} ); @@ -89,11 +87,3 @@ assert.eq.automsg( "1", "t.find( {$or:[{a:2},{a:1}]} ).toArray().length" ); assert.eq.automsg( "1", "t.count( {$or:[{a:2},{a:1}]} )" ); t.remove({}); - -assert.eq.automsg( "'BtreeCursor b_1'", "t.find( {$or:[{a:1}]} ).sort( {b:1} ).explain().cursor" ); -assert.eq.automsg( "'BtreeCursor b_1'", "t.find( {$or:[{}]} ).sort( {b:1} ).explain().cursor" ); -assert.eq.automsg( "'BtreeCursor b_1'", "t.find( {$or:[{b:1}]} ).sort( {b:1} ).explain().cursor" ); - -assert.eq.automsg( "'BtreeCursor b_1'", "t.find( {$or:[{a:1}]} ).hint( {b:1} ).explain().cursor" ); -assert.eq.automsg( "'BtreeCursor b_1'", "t.find( {$or:[{}]} ).hint( {b:1} ).explain().cursor" ); -assert.eq.automsg( "1", "t.find( {$or:[{b:1}]} ).hint( {b:1} ).explain().indexBounds.b[ 0 ][ 0 ]" ); diff --git a/jstests/core/or5.js b/jstests/core/or5.js index 6a7316787d4..8d9d8802860 100644 --- a/jstests/core/or5.js +++ b/jstests/core/or5.js @@ -4,9 +4,6 @@ t.drop(); t.ensureIndex( {a:1} ); t.ensureIndex( {b:1} ); -assert.eq.automsg( "'BasicCursor'", "t.find( {$or:[{a:2},{b:3},{}]} ).explain().cursor" ); -assert.eq.automsg( "'BasicCursor'", "t.find( {$or:[{a:2},{b:3},{c:4}]} ).explain().cursor" ); - t.ensureIndex( {c:1} ); t.save( {a:2} ); @@ -36,10 +33,6 @@ assert.eq.automsg( "6", "t.find( {$or:[{a:2},{b:3},{c:6}]} ).batchSize( i ).toAr t.ensureIndex( {z:"2d"} ); -assert.eq.automsg( "'GeoSearchCursor'", "t.find( {z:{$near:[50,50]},a:2} ).explain().cursor" ); -assert.eq.automsg( "'GeoSearchCursor'", "t.find( {z:{$near:[50,50]},$or:[{a:2}]} ).explain().cursor" ); -assert.eq.automsg( "'GeoSearchCursor'", "t.find( {$or:[{a:2}],z:{$near:[50,50]}} ).explain().cursor" ); -assert.eq.automsg( "'GeoSearchCursor'", "t.find( {$or:[{a:2},{b:3}],z:{$near:[50,50]}} ).explain().cursor" ); assert.throws.automsg( function() { return t.find( {$or:[{z:{$near:[50,50]}},{a:2}]} ).toArray(); } ); function reset() { diff --git a/jstests/core/or6.js b/jstests/core/or6.js index 43b75f467aa..2a8263e298f 100644 --- a/jstests/core/or6.js +++ b/jstests/core/or6.js @@ -1,23 +1,22 @@ -t = db.jstests_or6; -t.drop(); - -t.ensureIndex( {a:1} ); +// A few rooted $or cases. -assert.eq.automsg( "null", "t.find( {$or:[{a:1},{b:2}]} ).hint( {a:1} ).explain().clauses" ); +var t = db.jstests_orq; +t.drop(); -assert.eq.automsg( "'BasicCursor'", "t.find( {$or:[{a:1},{a:3}]} ).hint( {$natural:1} ).explain().cursor" ); +t.ensureIndex({a: 1, c: 1}); +t.ensureIndex({b: 1, c: 1}); -t.ensureIndex( {b:1} ); -assert.eq.automsg( "2", "t.find( {$or:[{a:1,b:5},{a:3,b:5}]} ).hint( {a:1} ).explain().clauses.length" ); +t.save({a: 1, c: 9}); +t.save({a: 1, c: 10}); +t.save({b: 2, c: 8}); +t.save({b: 2, c: 7}); -t.drop(); +// This can be answered using a merge sort. See SERVER-13715. +var cursor = t.find({$or: [{a: 1}, {b: 2}]}).sort({c: 1}); +for (var i = 7; i < 11; i++) { + assert.eq(i, cursor.next()["c"]); +} +assert(!cursor.hasNext()); -t.ensureIndex( {a:1,b:1} ); -assert.eq.automsg( "2", "t.find( {$or:[{a:{$in:[1,2]},b:5}, {a:2,b:6}]} )" + - ".hint({a:1,b:1}).explain().clauses.length" ); -assert.eq.automsg( "2", "t.find( {$or:[{a:{$gt:1,$lte:2},b:5}, {a:2,b:6}]} )" + - ".hint({a:1,b:1}).explain().clauses.length" ); -assert.eq.automsg( "2", "t.find( {$or:[{a:{$gt:1,$lte:3},b:5}, {a:2,b:6}]} )" + - ".hint({a:1,b:1}).explain().clauses.length" ); -assert.eq.automsg( "null", "t.find( {$or:[{a:{$in:[1,2]}}, {a:2}]} )" + - ".hint({a:1,b:1}).explain().clauses" ); +// SERVER-13715 +assert.eq(4, t.find({$or: [{a: 1}, {b: 2}]}).sort({a: 1}).itcount()); diff --git a/jstests/core/or9.js b/jstests/core/or9.js index 7318a532af4..c76c5407b6f 100644 --- a/jstests/core/or9.js +++ b/jstests/core/or9.js @@ -7,49 +7,43 @@ t.ensureIndex( {a:1,b:1} ); t.save( {a:2,b:2} ); -function check( a, b, q ) { +function check( a, q ) { count = a; - clauses = b; query = q; assert.eq.automsg( "count", "t.count( query )" ); - if ( clauses == 1 ) { - assert.eq.automsg( "undefined", "t.find( query ).explain().clauses" ); - } else { - assert.eq.automsg( "clauses", "t.find( query ).hint({a:1, b:1}).explain().clauses.length" ); - } } // SERVER-12594: there are two clauses in this case, because we do // not yet collapse OR of ANDs to a single ixscan. -check( 1, 2, { $or: [ { a: { $gte:1,$lte:3 } }, { a: 2 } ] } ); +check( 1, { $or: [ { a: { $gte:1,$lte:3 } }, { a: 2 } ] } ); -check( 1, 2, { $or: [ { a: { $gt:2,$lte:3 } }, { a: 2 } ] } ); +check( 1, { $or: [ { a: { $gt:2,$lte:3 } }, { a: 2 } ] } ); -check( 1, 1, { $or: [ { b: { $gte:1,$lte:3 } }, { b: 2 } ] } ); -check( 1, 1, { $or: [ { b: { $gte:2,$lte:3 } }, { b: 2 } ] } ); -check( 1, 1, { $or: [ { b: { $gt:2,$lte:3 } }, { b: 2 } ] } ); +check( 1, { $or: [ { b: { $gte:1,$lte:3 } }, { b: 2 } ] } ); +check( 1, { $or: [ { b: { $gte:2,$lte:3 } }, { b: 2 } ] } ); +check( 1, { $or: [ { b: { $gt:2,$lte:3 } }, { b: 2 } ] } ); // SERVER-12594: there are two clauses in this case, because we do // not yet collapse OR of ANDs to a single ixscan. -check( 1, 2, { $or: [ { a: { $gte:1,$lte:3 } }, { a: 2, b: 2 } ] } ); +check( 1, { $or: [ { a: { $gte:1,$lte:3 } }, { a: 2, b: 2 } ] } ); -check( 1, 2, { $or: [ { a: { $gte:1,$lte:3 }, b:3 }, { a: 2 } ] } ); +check( 1, { $or: [ { a: { $gte:1,$lte:3 }, b:3 }, { a: 2 } ] } ); -check( 1, 1, { $or: [ { b: { $gte:1,$lte:3 } }, { b: 2, a: 2 } ] } ); +check( 1, { $or: [ { b: { $gte:1,$lte:3 } }, { b: 2, a: 2 } ] } ); -check( 1, 1, { $or: [ { b: { $gte:1,$lte:3 }, a:3 }, { b: 2 } ] } ); +check( 1, { $or: [ { b: { $gte:1,$lte:3 }, a:3 }, { b: 2 } ] } ); -check( 1, 2, { $or: [ { a: { $gte:1,$lte:3 }, b: 3 }, { a: 2, b: 2 } ] } ); -check( 1, 2, { $or: [ { a: { $gte:2,$lte:3 }, b: 3 }, { a: 2, b: 2 } ] } ); +check( 1, { $or: [ { a: { $gte:1,$lte:3 }, b: 3 }, { a: 2, b: 2 } ] } ); +check( 1, { $or: [ { a: { $gte:2,$lte:3 }, b: 3 }, { a: 2, b: 2 } ] } ); // SERVER-12594: there are two clauses in this case, because we do // not yet collapse OR of ANDs to a single ixscan. -check( 1, 2, { $or: [ { a: { $gte:1,$lte:3 }, b: 2 }, { a: 2, b: 2 } ] } ); +check( 1, { $or: [ { a: { $gte:1,$lte:3 }, b: 2 }, { a: 2, b: 2 } ] } ); -check( 1, 2, { $or: [ { b: { $gte:1,$lte:3 }, a: 3 }, { a: 2, b: 2 } ] } ); -check( 1, 2, { $or: [ { b: { $gte:2,$lte:3 }, a: 3 }, { a: 2, b: 2 } ] } ); +check( 1, { $or: [ { b: { $gte:1,$lte:3 }, a: 3 }, { a: 2, b: 2 } ] } ); +check( 1, { $or: [ { b: { $gte:2,$lte:3 }, a: 3 }, { a: 2, b: 2 } ] } ); // SERVER-12594: there are two clauses in this case, because we do // not yet collapse OR of ANDs to a single ixscan. -check( 1, 2, { $or: [ { b: { $gte:1,$lte:3 }, a: 2 }, { a: 2, b: 2 } ] } ); +check( 1, { $or: [ { b: { $gte:1,$lte:3 }, a: 2 }, { a: 2, b: 2 } ] } ); t.remove({}); @@ -58,7 +52,7 @@ t.save( {a:5,b:1} ); // SERVER-12594: there are two clauses in the case below, because we do // not yet collapse OR of ANDs to a single ixscan. -check( 2, 2, { $or: [ { a: { $in:[1,5] }, b: { $in:[1,5] } }, { a: { $in:[1,5] }, b: { $in:[1,5] } } ] } ); +check( 2, { $or: [ { a: { $in:[1,5] }, b: { $in:[1,5] } }, { a: { $in:[1,5] }, b: { $in:[1,5] } } ] } ); -check( 2, 2, { $or: [ { a: { $in:[1] }, b: { $in:[1,5] } }, { a: { $in:[1,5] }, b: { $in:[1,5] } } ] } ); -check( 2, 2, { $or: [ { a: { $in:[1] }, b: { $in:[1] } }, { a: { $in:[1,5] }, b: { $in:[1,5] } } ] } ); +check( 2, { $or: [ { a: { $in:[1] }, b: { $in:[1,5] } }, { a: { $in:[1,5] }, b: { $in:[1,5] } } ] } ); +check( 2, { $or: [ { a: { $in:[1] }, b: { $in:[1] } }, { a: { $in:[1,5] }, b: { $in:[1,5] } } ] } ); diff --git a/jstests/core/orf.js b/jstests/core/orf.js index 720b5b31f0c..bae8c61f89a 100644 --- a/jstests/core/orf.js +++ b/jstests/core/orf.js @@ -15,13 +15,8 @@ a.forEach( function( x ) { t.save( x ); } ); // a series of _id index point intervals. explain = t.find( {$or:a} ).hint( {_id: 1} ).explain( true ); printjson( explain ); -assert.eq( 'BtreeCursor _id_', explain.cursor, 'cursor' ); -assert.eq( expectBounds, explain.indexBounds['_id'], 'indexBounds' ); -assert.eq( 200, explain.n, 'n' ); -assert.eq( 200, explain.nscanned, 'nscanned' ); -assert.eq( 200, explain.nscannedObjects, 'nscannedObjects' ); -assert.eq( false, explain.isMultiKey, 'isMultiKey' ); -assert.eq( false, explain.scanAndOrder, 'scanAndOrder' ); -assert.eq( false, explain.indexOnly, 'indexOnly' ); +assert.eq( 200, explain.executionStats.nReturned, 'n' ); +assert.eq( 200, explain.executionStats.totalKeysExamined, 'keys examined' ); +assert.eq( 200, explain.executionStats.totalDocsExamined, 'docs examined' ); assert.eq( 200, t.count( {$or:a} ) ); diff --git a/jstests/core/orl.js b/jstests/core/orl.js index 2726975d5aa..f76409d0d04 100644 --- a/jstests/core/orl.js +++ b/jstests/core/orl.js @@ -10,4 +10,4 @@ t.save( {a:{b:[1,2]}} ); // SERVER-3445 if ( 0 ) { assert( !t.find( {$or:[{'a.b':2,'a.c':3},{'a.b':2,'a.c':4}]} ).explain().clauses ); -}
\ No newline at end of file +} diff --git a/jstests/core/orq.js b/jstests/core/orq.js deleted file mode 100644 index 2a8263e298f..00000000000 --- a/jstests/core/orq.js +++ /dev/null @@ -1,22 +0,0 @@ -// A few rooted $or cases. - -var t = db.jstests_orq; -t.drop(); - -t.ensureIndex({a: 1, c: 1}); -t.ensureIndex({b: 1, c: 1}); - -t.save({a: 1, c: 9}); -t.save({a: 1, c: 10}); -t.save({b: 2, c: 8}); -t.save({b: 2, c: 7}); - -// This can be answered using a merge sort. See SERVER-13715. -var cursor = t.find({$or: [{a: 1}, {b: 2}]}).sort({c: 1}); -for (var i = 7; i < 11; i++) { - assert.eq(i, cursor.next()["c"]); -} -assert(!cursor.hasNext()); - -// SERVER-13715 -assert.eq(4, t.find({$or: [{a: 1}, {b: 2}]}).sort({a: 1}).itcount()); diff --git a/jstests/core/profile4.js b/jstests/core/profile4.js index ca27fd2e3ca..fa3fdaecc32 100644 --- a/jstests/core/profile4.js +++ b/jstests/core/profile4.js @@ -75,7 +75,7 @@ try { t.find().skip( 1 ).limit( 4 ).itcount(); checkLastOp( [ [ "ntoreturn", 4 ], [ "ntoskip", 1 ], - [ "nscanned", 3 ], + [ "nscannedObjects", 3 ], [ "nreturned", 2 ] ] ); t.find().batchSize( 2 ).next(); diff --git a/jstests/core/proj_key1.js b/jstests/core/proj_key1.js index ad944f71827..c0720ed0fcb 100644 --- a/jstests/core/proj_key1.js +++ b/jstests/core/proj_key1.js @@ -9,20 +9,9 @@ for ( i=0; i<10; i++ ){ t.insert( { a : i , b : i } ); } -assert( ! t.find( {} , { a : 1 } ).explain().indexOnly , "A1" ) - t.ensureIndex( { a : 1 } ) -assert( t.find( { a : { $gte : 0 } } , { a : 1 , _id : 0 } ).explain().indexOnly , "A2" ) - -assert( ! t.find( { a : { $gte : 0 } } , { a : 1 } ).explain().indexOnly , "A3" ) // because id _id - // assert( t.find( {} , { a : 1 , _id : 0 } ).explain().indexOnly , "A4" ); // TODO: need to modify query optimier SERVER-2109 assert.eq( as , t.find( { a : { $gte : 0 } } , { a : 1 , _id : 0 } ).toArray() , "B1" ) assert.eq( as , t.find( { a : { $gte : 0 } } , { a : 1 , _id : 0 } ).batchSize(2).toArray() , "B1" ) - - - - - diff --git a/jstests/core/regex3.js b/jstests/core/regex3.js index 5ac8fab4c40..418492ce7f5 100644 --- a/jstests/core/regex3.js +++ b/jstests/core/regex3.js @@ -8,10 +8,12 @@ t.save( { name : "bob" } ); t.save( { name : "aaron" } ); assert.eq( 2 , t.find( { name : /^e.*/ } ).itcount() , "no index count" ); -assert.eq( 4 , t.find( { name : /^e.*/ } ).explain().nscanned , "no index explain" ); +assert.eq( 4 , t.find( { name : /^e.*/ } ).explain().executionStats.totalDocsExamined , + "no index explain" ); t.ensureIndex( { name : 1 } ); assert.eq( 2 , t.find( { name : /^e.*/ } ).itcount() , "index count" ); -assert.eq( 2 , t.find( { name : /^e.*/ } ).explain().nscanned , "index explain" ); // SERVER-239 +assert.eq( 2 , t.find( { name : /^e.*/ } ).explain().executionStats.totalKeysExamined , + "index explain" ); // SERVER-239 t.drop(); @@ -23,7 +25,8 @@ t.save( { name : "c" } ); assert.eq( 3 , t.find( { name : /^aa*/ } ).itcount() , "B ni" ); t.ensureIndex( { name : 1 } ); assert.eq( 3 , t.find( { name : /^aa*/ } ).itcount() , "B i 1" ); -assert.eq( 4 , t.find( { name : /^aa*/ } ).explain().nscanned , "B i 1 e" ); +assert.eq( 4 , t.find( { name : /^aa*/ } ).explain().executionStats.totalKeysExamined , + "B i 1 e" ); assert.eq( 2 , t.find( { name : /^a[ab]/ } ).itcount() , "B i 2" ); assert.eq( 2 , t.find( { name : /^a[bc]/ } ).itcount() , "B i 3" ); diff --git a/jstests/core/regex4.js b/jstests/core/regex4.js index fc26d691c91..e95daeafe7c 100644 --- a/jstests/core/regex4.js +++ b/jstests/core/regex4.js @@ -8,11 +8,13 @@ t.save( { name : "bob" } ); t.save( { name : "aaron" } ); assert.eq( 2 , t.find( { name : /^e.*/ } ).count() , "no index count" ); -assert.eq( 4 , t.find( { name : /^e.*/ } ).explain().nscanned , "no index explain" ); +assert.eq( 4 , t.find( { name : /^e.*/ } ).explain().executionStats.totalDocsExamined , + "no index explain" ); //assert.eq( 2 , t.find( { name : { $ne : /^e.*/ } } ).count() , "no index count ne" ); // SERVER-251 t.ensureIndex( { name : 1 } ); assert.eq( 2 , t.find( { name : /^e.*/ } ).count() , "index count" ); -assert.eq( 2 , t.find( { name : /^e.*/ } ).explain().nscanned , "index explain" ); // SERVER-239 +assert.eq( 2 , t.find( { name : /^e.*/ } ).explain().executionStats.totalKeysExamined , + "index explain" ); // SERVER-239 //assert.eq( 2 , t.find( { name : { $ne : /^e.*/ } } ).count() , "index count ne" ); // SERVER-251 diff --git a/jstests/core/regex5.js b/jstests/core/regex5.js index 9f2549d7146..fab3eb9973c 100644 --- a/jstests/core/regex5.js +++ b/jstests/core/regex5.js @@ -36,18 +36,6 @@ t.ensureIndex( {x:1} ); print( "now indexed" ); doit(); -// check bound unions SERVER-322 -assert.eq( { - x:[[1,1], - [2.5,2.5], - ["a","a"], - ["b","e"], - [/^b/,/^b/], - [/^c/,/^c/], - [/^d/,/^d/]] - }, - t.find( { x : { $in: [ 1, 2.5, "a", "b", /^b/, /^c/, /^d/ ] } } ).explain().indexBounds ); - // SERVER-505 assert.eq( 0, t.find( { x : { $all: [ "a", /^a/ ] } } ).itcount()); assert.eq( 2, t.find( { x : { $all: [ /^a/ ] } } ).itcount()); diff --git a/jstests/core/regex6.js b/jstests/core/regex6.js index 54143248398..9ffa7499deb 100644 --- a/jstests/core/regex6.js +++ b/jstests/core/regex6.js @@ -11,19 +11,31 @@ t.save( { name : "[with]some?symbols" } ); t.ensureIndex( { name : 1 } ); assert.eq( 0 , t.find( { name : /^\// } ).count() , "index count" ); -assert.eq( 1 , t.find( { name : /^\// } ).explain().nscanned , "index explain 1" ); -assert.eq( 0 , t.find( { name : /^é/ } ).explain().nscanned , "index explain 2" ); -assert.eq( 0 , t.find( { name : /^\é/ } ).explain().nscanned , "index explain 3" ); -assert.eq( 1 , t.find( { name : /^\./ } ).explain().nscanned , "index explain 4" ); -assert.eq( 5 , t.find( { name : /^./ } ).explain().nscanned , "index explain 5" ); +assert.eq( 1 , t.find( { name : /^\// } ).explain().executionStats.totalKeysExamined , + "index explain 1" ); +assert.eq( 0 , t.find( { name : /^é/ } ).explain().executionStats.totalKeysExamined , + "index explain 2" ); +assert.eq( 0 , t.find( { name : /^\é/ } ).explain().executionStats.totalKeysExamined , + "index explain 3" ); +assert.eq( 1 , t.find( { name : /^\./ } ).explain().executionStats.totalKeysExamined , + "index explain 4" ); +assert.eq( 5 , t.find( { name : /^./ } ).explain().executionStats.totalKeysExamined , + "index explain 5" ); // SERVER-2862 assert.eq( 0 , t.find( { name : /^\Qblah\E/ } ).count() , "index explain 6" ); -assert.eq( 1 , t.find( { name : /^\Qblah\E/ } ).explain().nscanned , "index explain 6" ); -assert.eq( 1 , t.find( { name : /^blah/ } ).explain().nscanned , "index explain 6" ); -assert.eq( 1 , t.find( { name : /^\Q[\Ewi\Qth]some?s\Eym/ } ).count() , "index explain 6" ); -assert.eq( 2 , t.find( { name : /^\Q[\Ewi\Qth]some?s\Eym/ } ).explain().nscanned , "index explain 6" ); -assert.eq( 2 , t.find( { name : /^bob/ } ).explain().nscanned , "index explain 6" ); // proof nscanned == count+1 +assert.eq( 1 , t.find( { name : /^\Qblah\E/ } ).explain().executionStats.totalKeysExamined , + "index explain 6" ); +assert.eq( 1 , t.find( { name : /^blah/ } ).explain().executionStats.totalKeysExamined , + "index explain 6" ); +assert.eq( 1 , t.find( { name : /^\Q[\Ewi\Qth]some?s\Eym/ } ).count() , "index count 2" ); +assert.eq( 2 , t.find( { name : /^\Q[\Ewi\Qth]some?s\Eym/ } ).explain() + .executionStats.totalKeysExamined , + "index explain 6" ); +assert.eq( 2 , t.find( { name : /^bob/ } ).explain().executionStats.totalKeysExamined , + "index explain 6" ); // proof executionStats.totalKeysExamined == count+1 -assert.eq( 1, t.find( { name : { $regex : "^e", $gte: "emily" } } ).explain().nscanned , "ie7" ); -assert.eq( 1, t.find( { name : { $gt : "a", $regex: "^emily" } } ).explain().nscanned , "ie7" ); +assert.eq( 1, t.find( { name : { $regex : "^e", $gte: "emily" } } ).explain() + .executionStats.totalKeysExamined , "ie7" ); +assert.eq( 1, t.find( { name : { $gt : "a", $regex: "^emily" } } ).explain() + .executionStats.totalKeysExamined , "ie7" ); diff --git a/jstests/core/rename.js b/jstests/core/rename.js index a8eb6c911c4..9c3ce2c18b2 100644 --- a/jstests/core/rename.js +++ b/jstests/core/rename.js @@ -24,7 +24,6 @@ assert( db.getCollectionNames().indexOf( "jstests_rename_b" ) >= 0 ); assert( db.getCollectionNames().indexOf( "jstests_rename_a" ) < 0 ); assert.eq( 3, db.jstests_rename_b.getIndexes().length ); assert.eq( 0, db.jstests_rename_a.getIndexes().length ); -assert( b.find( {a:1} ).explain().cursor.match( /^BtreeCursor/ ) ); // now try renaming a capped collection diff --git a/jstests/core/rename7.js b/jstests/core/rename7.js index df4267a7583..ed64d2b8ec7 100644 --- a/jstests/core/rename7.js +++ b/jstests/core/rename7.js @@ -27,7 +27,6 @@ assert( db_a.getCollectionNames().indexOf( "rename7" ) < 0 ); assert.eq( 3, b.find().count() ); assert( db_b.getCollectionNames().indexOf( "rename7" ) >= 0 ); -assert( b.find( {a: 1} ).explain().cursor.match( /^BtreeCursor/ ) ); a.drop(); b.drop(); diff --git a/jstests/core/repair.js b/jstests/core/repair.js deleted file mode 100644 index 52dcf3ceafc..00000000000 --- a/jstests/core/repair.js +++ /dev/null @@ -1,30 +0,0 @@ -mydb = db.getSisterDB( "repair_test1" ) - -t = mydb.jstests_repair; -t.drop(); - -t.save( { i:1 } ); -doc = t.findOne(); -t.ensureIndex( { i : 1 } ); -assert.eq( 2, t.getIndexes().length ); -ex = t.find( { i : 1 } ).explain(); - -assert.commandWorked( mydb.repairDatabase() ); - -v = t.validate(); -assert( v.valid , "not valid! " + tojson( v ) ); - -assert.eq( 1, t.count() ); -assert.eq( doc, t.findOne() ); - -assert.eq( 2, t.getIndexes().length, tojson( t.getIndexes() ) ); -var explainAfterRepair = t.find( { i : 1 } ).explain(); - -// Remove "millis" and "nYields" fields. We're interested in the other fields. -// It's not relevant for both explain() operations to have -// the same execution time. -delete ex[ "millis" ]; -delete ex[ "nYields" ]; -delete explainAfterRepair[ "millis" ]; -delete explainAfterRepair[ "nYields" ]; -assert.eq( ex, explainAfterRepair ); diff --git a/jstests/core/sortg.js b/jstests/core/sortg.js index bde4ad70061..52b5129f870 100644 --- a/jstests/core/sortg.js +++ b/jstests/core/sortg.js @@ -19,16 +19,11 @@ function memoryException( sortSpec, querySpec ) { t.find( querySpec ).sort( sortSpec ).batchSize( 1000 ).itcount() } ); assert( ex.toString().match( /sort/ ) ); - assert.throws( function() { - t.find( querySpec ).sort( sortSpec ).batchSize( 1000 ).explain( true ) - } ); - assert( ex.toString().match( /sort/ ) ); } function noMemoryException( sortSpec, querySpec ) { querySpec = querySpec || {}; t.find( querySpec ).sort( sortSpec ).batchSize( 1000 ).itcount(); - t.find( querySpec ).sort( sortSpec ).batchSize( 1000 ).explain( true ); } // Unindexed sorts. diff --git a/jstests/core/sorth.js b/jstests/core/sorth.js index 1072975a3ec..e520ee50454 100644 --- a/jstests/core/sorth.js +++ b/jstests/core/sorth.js @@ -33,8 +33,8 @@ function find( query ) { function checkMatches( expectedMatch, query ) { result = find( query ).toArray(); assertMatches( expectedMatch, result ); - explain = find( query ).explain(); - assert.eq( expectedMatch.length || 1, explain.n ); + var count = find( query ).itcount(); + assert.eq( expectedMatch.length || 1, count ); } /** Reset data, index, and _sort and _hint globals. */ diff --git a/jstests/core/sortk.js b/jstests/core/sortk.js index 3895a34c3ac..20ef08f7cca 100644 --- a/jstests/core/sortk.js +++ b/jstests/core/sortk.js @@ -40,7 +40,7 @@ assert.eq( 1, simpleQueryWithLimit( -1 ).skip( 1 )[ 0 ].b ); // No limit is applied. assert.eq( 6, simpleQueryWithLimit( 0 ).itcount() ); -assert.eq( 6, simpleQueryWithLimit( 0 ).explain().nscanned ); +assert.eq( 6, simpleQueryWithLimit( 0 ).explain().executionStats.totalKeysExamined ); assert.eq( 5, simpleQueryWithLimit( 0 ).skip( 1 ).itcount() ); // The query has additional constriants, preventing limit optimization. @@ -55,7 +55,7 @@ assert.eq( 0, simpleQuery( {}, { a:-1, b:1 } ).limit( -1 )[ 0 ].b ); // Without a hint, multiple cursors are attempted. assert.eq( 0, t.find( { a:{ $in:[ 1, 2 ] } } ).sort( { b:1 } ).limit( -1 )[ 0 ].b ); explain = t.find( { a:{ $in:[ 1, 2 ] } } ).sort( { b:1 } ).limit( -1 ).explain( true ); -assert.eq( 1, explain.n ); +assert.eq( 1, explain.executionStats.nReturned ); // The expected first result now comes from the first interval. t.remove( { b:0 } ); diff --git a/jstests/core/type1.js b/jstests/core/type1.js index 518e36728e7..7f101a2c027 100644 --- a/jstests/core/type1.js +++ b/jstests/core/type1.js @@ -11,7 +11,6 @@ assert.eq( 4 , t.find().count() , "A1" ); assert.eq( 1 , t.find( { x : { $type : 1 } } ).count() , "A2" ); assert.eq( 3 , t.find( { x : { $type : 2 } } ).count() , "A3" ); assert.eq( 0 , t.find( { x : { $type : 3 } } ).count() , "A4" ); -assert.eq( 4 , t.find( { x : { $type : 1 } } ).explain().nscanned , "A5" ); t.ensureIndex( { x : 1 } ); @@ -20,5 +19,4 @@ assert.eq( 4 , t.find().count() , "B1" ); assert.eq( 1 , t.find( { x : { $type : 1 } } ).count() , "B2" ); assert.eq( 3 , t.find( { x : { $type : 2 } } ).count() , "B3" ); assert.eq( 0 , t.find( { x : { $type : 3 } } ).count() , "B4" ); -assert.eq( 1 , t.find( { x : { $type : 1 } } ).explain().nscanned , "B5" ); -assert.eq( 1 , t.find( { x : { $regex:"f", $type : 2 } } ).count() , "B3" );
\ No newline at end of file +assert.eq( 1 , t.find( { x : { $regex:"f", $type : 2 } } ).count() , "B3" ); diff --git a/jstests/core/type3.js b/jstests/core/type3.js index 82a8b8ae7fc..59eb89f642e 100644 --- a/jstests/core/type3.js +++ b/jstests/core/type3.js @@ -21,13 +21,11 @@ assert.eq( 1, t.find( {a:{$type:11}} ).hint( {a:1} ).itcount() ); // Type jstNULL t.remove({}); -assert.eq( [[null,null]], t.find( {a:{$type:10}} ).hint( {a:1} ).explain().indexBounds.a ); +t.save( {a:null} ); +assert.eq( 1, t.find( {a:{$type:10}} ).hint( {a:1} ).itcount() ); // Type Undefined t.remove({}); -// 'null' is the client friendly version of undefined. -assert.eq( [[null,null]], t.find( {a:{$type:6}} ).hint( {a:1} ).explain().indexBounds.a ); - t.save( {a:undefined} ); assert.eq( 1, t.find( {a:{$type:6}} ).hint( {a:1} ).itcount() ); @@ -35,12 +33,6 @@ assert.eq( 1, t.find( {a:{$type:6}} ).hint( {a:1} ).itcount() ); t.save( {a:null} ); assert.eq( 1, t.find( {a:{$type:6}} ).hint( {a:1} ).itcount() ); -t.remove({}); -// Type MinKey -assert.eq( [[{$minElement:1},{$minElement:1}]], t.find( {a:{$type:-1}} ).hint( {a:1} ).explain().indexBounds.a ); -// Type MaxKey -assert.eq( [[{$maxElement:1},{$maxElement:1}]], t.find( {a:{$type:127}} ).hint( {a:1} ).explain().indexBounds.a ); - // Type Timestamp t.remove({}); t.save( {a:new Timestamp()} ); diff --git a/jstests/core/useindexonobjgtlt.js b/jstests/core/useindexonobjgtlt.js index 06e94a812f6..e407ad7cf0a 100755 --- a/jstests/core/useindexonobjgtlt.js +++ b/jstests/core/useindexonobjgtlt.js @@ -5,11 +5,10 @@ t.ensureIndex( { metro : 1 } ) assert( db.factories.find().count() )
-assert( db.factories.find( { metro: { city: "New York", state: "NY" } } ).count() )
-
-assert( db.factories.find( { metro: { city: "New York", state: "NY" } } ).explain().cursor == "BtreeCursor metro_1" )
-
-assert( db.factories.find( { metro: { $gte : { city: "New York" } } } ).explain().cursor == "BtreeCursor metro_1" )
-
-assert( db.factories.find( { metro: { $gte : { city: "New York" } } } ).count() == 1 )
+assert.eq( 1, db.factories.find( { metro: { city: "New York", state: "NY" } } )
+ .hint({metro: 1})
+ .count() )
+assert.eq( 1, db.factories.find( { metro: { $gte : { city: "New York" } } } )
+ .hint({metro: 1})
+ .count() )
|