-
在使用MOngoDB时,目前需要用查询条件和
_id
来分页,数据库有一个birthDay_str_1_status_1_activeTime_1
这三个字段的索引,我的查询条件是:db.getCollection('T_User').find({ "birthDay_str": "0727", "status": "APPLY", "_id": { $gte: "570e08ca00b04947c827ea2e" } }).sort({ "_id": 1 }).explain()
返回结果如下,对mongoDB索引不是很了解,谁能回答下底下的内容是什么意思
返回结果如下:
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "ossDev.T_User",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"birthDay_str" : {
"$eq" : "0727"
}
},
{
"status" : {
"$eq" : "APPLY"
}
},
{
"_id" : {
"$gte" : "570e08ca00b04947c827ea2e"
}
}
]
},
"winningPlan" : {
"stage" : "SORT",
"sortPattern" : {
"_id" : 1.0
},
"inputStage" : {
"stage" : "SORT_KEY_GENERATOR",
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"_id" : {
"$gte" : "570e08ca00b04947c827ea2e"
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"birthDay_str" : 1.0,
"status" : 1.0,
"activeTime" : 1.0
},
"indexName" : "birthDay_str_1_status_1_activeTime_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"birthDay_str" : [
"[\"0727\", \"0727\"]"
],
"status" : [
"[\"APPLY\", \"APPLY\"]"
],
"activeTime" : [
"[MinKey, MaxKey]"
]
}
}
}
}
},
"rejectedPlans" : [
{
"stage" : "FETCH",
"filter" : {
"$and" : [
{
"birthDay_str" : {
"$eq" : "0727"
}
},
{
"status" : {
"$eq" : "APPLY"
}
}
]
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"_id" : 1
},
"indexName" : "_id_",
"isMultiKey" : false,
"isUnique" : true,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"_id" : [
"[\"570e08ca00b04947c827ea2e\", {})"
]
}
}
},
{
"stage" : "SORT",
"sortPattern" : {
"_id" : 1.0
},
"inputStage" : {
"stage" : "SORT_KEY_GENERATOR",
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"$and" : [
{
"birthDay_str" : {
"$eq" : "0727"
}
},
{
"_id" : {
"$gte" : "570e08ca00b04947c827ea2e"
}
}
]
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"status" : 1.0
},
"indexName" : "status_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"status" : [
"[\"APPLY\", \"APPLY\"]"
]
}
}
}
}
},
{
"stage" : "SORT",
"sortPattern" : {
"_id" : 1.0
},
"inputStage" : {
"stage" : "SORT_KEY_GENERATOR",
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"$and" : [
{
"birthDay_str" : {
"$eq" : "0727"
}
},
{
"_id" : {
"$gte" : "570e08ca00b04947c827ea2e"
}
}
]
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"status" : 1.0,
"userSequence" : 1.0
},
"indexName" : "status_1_userSequence_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"status" : [
"[\"APPLY\", \"APPLY\"]"
],
"userSequence" : [
"[MinKey, MaxKey]"
]
}
}
}
}
}
]
},
"serverInfo" : {
"host" : "maomaodb02",
"port" : 27017,
"version" : "3.2.4",
"gitVersion" : "e2ee9ffcf9f5a94fad76802e28cc978718bb7a30"
},
"ok" : 1.0
}
其中:
"winningPlan" : {
"stage" : "SORT",
"sortPattern" : {
"_id" : 1.0
},
"inputStage" : {
"stage" : "SORT_KEY_GENERATOR",
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"_id" : {
"$gte" : "570e08ca00b04947c827ea2e"
}
},
显示的状态为SORT
是什么意思,再往下面状态又为IXSCAN
,请问是通过哪一块的信息,判断是否用到了索引?
同事stage状态为IXSCAN
、FETCH
、SORT
、分别代表什么意思?
简单地讲,看到
{stage: "SORT"}
就代表有一个阶段是单独在做内存排序而没有用到索引。而看到IXSCAN
和使用内存排序并不矛盾,这里用到索引是在用它过滤数据:所以查询部分是用到了
birthDay_str_1_status_1_activeTime_1
中的birthDay_str
+status
两个来过滤数据,当然你的条件中还有{_id: {$gte: "570e08ca00b04947c827ea2e"}}
,所以这个索引虽然命中了,但是只能说对你的查询有一定的帮助,效率怎么样还不好说(需要看explain("executionStats")
)。不管怎么说,这个索引对排序是没有任何帮助的。再来说
FETCH
。它的意思是如字面意思:抓取数据。假设你在A
字段上建立了索引,这个索引是个BTree,但是你可以把它想象成一个排好序的数组,这样在做搜索的时候就可以折半查找,从而节省搜索时间,时间复杂度从O(n)
变成O(log2(n))
,这也是索引提高查询效率的原因由来。但是数组里面只有A
字段的值,不可能也没有必要包含整个文档的内容,所以在数组中除了存放A的值外,系统会额外存一个data page,数据页,意思就是:当你需要A以外的其他值的时候去这里找整个文档。这样一来就有了FETCH
这个动作。我没有办法在这里解释怎么索引是如何工作的,但是你可以搜一些文档看看BTree索引的工作原理,相信会对索引如何工作有更好的理解。
最后提一下满足你那个查询和排序的最合适的索引是:
还有一点不知道是你手误或者是没有注意,默认情况下
_id
是ObjectId
而不是字符串(除非你有特别修改),所以条件中的正确写法应该是: