原文Explain分析实例
表中数据如下(简单测试用例,仅10条数据,主要是对explain分析的逻辑进行解析):
{ “_id” : ObjectId(“55b86d6bd7e3f4ccaaf20d70”), “a” : 1, “b” : 1, “c” : 1 }
{ “_id” : ObjectId(“55b86d6fd7e3f4ccaaf20d71”), “a” : 1, “b” : 2, “c” : 2 }
{ “_id” : ObjectId(“55b86d72d7e3f4ccaaf20d72”), “a” : 1, “b” : 3, “c” : 3 }
{ “_id” : ObjectId(“55b86d74d7e3f4ccaaf20d73”), “a” : 4, “b” : 2, “c” : 3 }
{ “_id” : ObjectId(“55b86d75d7e3f4ccaaf20d74”), “a” : 4, “b” : 2, “c” : 5 }
{ “_id” : ObjectId(“55b86d77d7e3f4ccaaf20d75”), “a” : 4, “b” : 2, “c” : 5 }
{ “_id” : ObjectId(“55b879b442bfd1a462bd8990”), “a” : 2, “b” : 1, “c” : 1 }
{ “_id” : ObjectId(“55b87fe842bfd1a462bd8991”), “a” : 1, “b” : 9, “c” : 1 }
{ “_id” : ObjectId(“55b87fe942bfd1a462bd8992”), “a” : 1, “b” : 9, “c” : 1 }
{ “_id” : ObjectId(“55b87fe942bfd1a462bd8993”), “a” : 1, “b” : 9, “c” : 1 }
查询语句:
db.d.find({a:1,b:{$lt:3}}).sort({c:-1})
首先,我们看看没有index时候的查询计划
“executionStats” : {
“executionSuccess” : true,
“nReturned” : 2,
“executionTimeMillis” : 0,
“totalKeysExamined” : 0,
“totalDocsExamined” : 10,
“executionStages” : {
“stage” : “SORT”,
“nReturned” : 2,
…
“sortPattern” : {
“c” : -1
},
“memUsage” : 126,
“memLimit” : 33554432,
“inputStage” : {
“stage” : “COLLSCAN”,
“filter” : {
“and” : [
{
“a” : {
“eq” : 1
}
},
{
“b” : {
“$lt” : 3
}
}
]
},
“nReturned” : 2,
…
“direction” : “forward”,
“docsExamined” : 10
}
nReturned为2,符合的条件的返回为2条。
totalKeysExamined为0,没有使用index。
totalDocsExamined为10,扫描了所有记录。
executionStages.stage为SORT,未使用index的sort,占用的内存与内存限制为”memUsage” : 126, “memLimit” : 33554432。
executionStages.inputStage.stage为COLLSCAN,全表扫描,扫描条件为
“filter” : {
“and” : [
{
“a” : {
“eq” : 1
}
},
{
“b” : {
“$lt” : 3
}
}
]
},
很明显,没有index的时候,进行了全表扫描,没有使用到index,在内存中sort,很显然,和都是不可取的。
下面,我们来对sort项c加一个索引
db.d.ensureIndex({c:1})
再来看看执行计划
“executionStats” : {
“executionSuccess” : true,
“nReturned” : 2,
“executionTimeMillis” : 1,
“totalKeysExamined” : 10,
“totalDocsExamined” : 10,
“executionStages” : {
“stage” : “FETCH”,
“filter” : {
“and” : [
{
“a” : {
“eq” : 1
}
},
{
“b” : {
“$lt” : 3
}
}
]
},
“nReturned” : 2,
…
“inputStage” : {
“stage” : “IXSCAN”,
“nReturned” : 10,
…
“keyPattern” : {
“c” : 1
},
“indexName” : “c_1”,
“isMultiKey” : false,
“direction” : “backward”,
“indexBounds” : {
“c” : [
“[MaxKey, MinKey]”
]
},
我们发现,Stage没有了SORT,因为我们sort字段有了index,但是由于查询还是没有index,故totalDocsExamined还是10,但是由于sort用了index,totalKeysExamined也是10,但是仅对sort排序做了优化,查询性能还是一样的低效。
接下来, 我们对查询条件做index(做多种index方案寻找最优)
我们的查询语句依然是:
db.d.find({a:1,b:{$lt:3}}).sort({c:-1})
使用db.d.ensureIndex({b:1,a:1,c:1})索引的执行计划:
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 2,
"executionTimeMillis" : 0,
"totalKeysExamined" : 4,
"totalDocsExamined" : 2,
"executionStages" : {
"stage" : "SORT",
"nReturned" : 2,
...
"sortPattern" : {
"c" : -1
},
"memUsage" : 126,
"memLimit" : 33554432,
"inputStage" : {
"stage" : "FETCH",
"nReturned" : 2,
...
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 2,
...
"keyPattern" : {
"b" : 1,
"a" : 1,
"c" : 1
},
"indexName" : "b_1_a_1_c_1",
"isMultiKey" : false,
"direction" : "forward",
"indexBounds" : {
"b" : [
"[-inf.0, 3.0)"
],
"a" : [
"[1.0, 1.0]"
],
"c" : [
"[MinKey, MaxKey]"
]
},
我们可以看到
nReturned为2,返回2条记录
totalKeysExamined为4,扫描了4个index
totalDocsExamined为2,扫描了2个docs
此时nReturned=totalDocsExamined