|
This issue does not affect the revamped explain which will be released with version 2.8.0. (Work for the revamped explain was done under SERVER-10448, so please refer to this ticket and its subtasks for details.) Resolving as a duplicate.
Note that in the new explain, the executionStats.allPlansExecution field reports stats captured during the query optimizer's trial period. It contains partial execution information for both the winning plan and the rejected plans. Therefore, it is expected behavior that, using the repro in the description of the ticket, the nReturned values are 101 rather than 1000:
"allPlansExecution" : [
|
{
|
"nReturned" : 101, // <===================== This is correct behavior (works this way by design).
|
"executionTimeMillisEstimate" : 10,
|
"totalKeysExamined" : 1000,
|
"totalDocsExamined" : 1000,
|
"executionStages" : {
|
"stage" : "SORT",
|
"nReturned" : 101,
|
"executionTimeMillisEstimate" : 10,
|
"works" : 1103,
|
"advanced" : 101,
|
"needTime" : 1001,
|
"needFetch" : 0,
|
"saveState" : 25,
|
"restoreState" : 25,
|
"isEOF" : 0,
|
"invalidates" : 0,
|
"sortPattern" : {
|
"z" : 1
|
},
|
"memUsage" : 52000,
|
"memLimit" : 33554432,
|
"inputStage" : {
|
"stage" : "KEEP_MUTATIONS",
|
"nReturned" : 1000,
|
"executionTimeMillisEstimate" : 10,
|
"works" : 1001,
|
"advanced" : 1000,
|
"needTime" : 0,
|
"needFetch" : 0,
|
"saveState" : 25,
|
"restoreState" : 25,
|
"isEOF" : 1,
|
"invalidates" : 0,
|
"inputStage" : {
|
"stage" : "FETCH",
|
"filter" : {
|
"b" : {
|
"$gte" : 0
|
}
|
},
|
"nReturned" : 1000,
|
"executionTimeMillisEstimate" : 10,
|
"works" : 1001,
|
"advanced" : 1000,
|
"needTime" : 0,
|
"needFetch" : 0,
|
"saveState" : 25,
|
"restoreState" : 25,
|
"isEOF" : 1,
|
"invalidates" : 0,
|
"docsExamined" : 1000,
|
"alreadyHasObj" : 0,
|
"inputStage" : {
|
"stage" : "IXSCAN",
|
"nReturned" : 1000,
|
"executionTimeMillisEstimate" : 10,
|
"works" : 1000,
|
"advanced" : 1000,
|
"needTime" : 0,
|
"needFetch" : 0,
|
"saveState" : 25,
|
"restoreState" : 25,
|
"isEOF" : 1,
|
"invalidates" : 0,
|
"keyPattern" : {
|
"a" : 1
|
},
|
"indexName" : "a_1",
|
"isMultiKey" : false,
|
"direction" : "forward",
|
"indexBounds" : {
|
"a" : [
|
"[0.0, inf.0]"
|
]
|
},
|
"keysExamined" : 1000,
|
"dupsTested" : 0,
|
"dupsDropped" : 0,
|
"seenInvalidated" : 0,
|
"matchTested" : 0
|
}
|
}
|
}
|
}
|
},
|
{
|
"nReturned" : 101, // <===================== This is correct behavior (works this way by design).
|
"executionTimeMillisEstimate" : 0,
|
"totalKeysExamined" : 1000,
|
"totalDocsExamined" : 1000,
|
"executionStages" : {
|
"stage" : "SORT",
|
"nReturned" : 101,
|
"executionTimeMillisEstimate" : 0,
|
"works" : 1103,
|
"advanced" : 101,
|
"needTime" : 1001,
|
"needFetch" : 0,
|
"saveState" : 17,
|
"restoreState" : 17,
|
"isEOF" : 0,
|
"invalidates" : 0,
|
"sortPattern" : {
|
"z" : 1
|
},
|
"memUsage" : 52000,
|
"memLimit" : 33554432,
|
"inputStage" : {
|
"stage" : "KEEP_MUTATIONS",
|
"nReturned" : 1000,
|
"executionTimeMillisEstimate" : 0,
|
"works" : 1001,
|
"advanced" : 1000,
|
"needTime" : 0,
|
"needFetch" : 0,
|
"saveState" : 17,
|
"restoreState" : 17,
|
"isEOF" : 1,
|
"invalidates" : 0,
|
"inputStage" : {
|
"stage" : "FETCH",
|
"filter" : {
|
"a" : {
|
"$gte" : 0
|
}
|
},
|
"nReturned" : 1000,
|
"executionTimeMillisEstimate" : 0,
|
"works" : 1001,
|
"advanced" : 1000,
|
"needTime" : 0,
|
"needFetch" : 0,
|
"saveState" : 17,
|
"restoreState" : 17,
|
"isEOF" : 1,
|
"invalidates" : 0,
|
"docsExamined" : 1000,
|
"alreadyHasObj" : 0,
|
"inputStage" : {
|
"stage" : "IXSCAN",
|
"nReturned" : 1000,
|
"executionTimeMillisEstimate" : 0,
|
"works" : 1000,
|
"advanced" : 1000,
|
"needTime" : 0,
|
"needFetch" : 0,
|
"saveState" : 17,
|
"restoreState" : 17,
|
"isEOF" : 1,
|
"invalidates" : 0,
|
"keyPattern" : {
|
"b" : 1
|
},
|
"indexName" : "b_1",
|
"isMultiKey" : false,
|
"direction" : "forward",
|
"indexBounds" : {
|
"b" : [
|
"[0.0, inf.0]"
|
]
|
},
|
"keysExamined" : 1000,
|
"dupsTested" : 0,
|
"dupsDropped" : 0,
|
"seenInvalidated" : 0,
|
"matchTested" : 0
|
}
|
}
|
}
|
}
|
}
|
]
|
The rationale behind this behavior is that the information given by allPlansExecution can be very useful for diagnosing why a plan was chosen by the optimizer. Previous versions of explain could tell you which plan was chosen and which were rejected, but it was difficult to gain insight into why this decision was made.
|