要了解 mongo 查询的幕后情况,您可以使用explain。例如,考虑以下查询:
db.getCollection('users').find({"name":"ana"})
查询非索引字段。您可以在此查询上使用说明如下:
db.getCollection('users').find({"name":"ana"}).explain("executionStats")
部分结果是:
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "anonymous-chat.users",
"indexFilterSet" : false,
"parsedQuery" : {
"name" : {
"$eq" : "ana"
}
},
"winningPlan" : {
"stage" : "COLLSCAN",
"filter" : {
"name" : {
"$eq" : "ana"
}
},
"direction" : "forward"
},
"rejectedPlans" : []
},
如您所见,这里我们有一个COLLSCAN,它是一个集合扫描。
现在我们只需查询 _id 并查看结果:
db.getCollection('users').find({"_id":ObjectId("5ee9b6c125b9a9a426d9965f")}).explain("executionStats")
结果如下:
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "anonymous-chat.users",
"indexFilterSet" : false,
"parsedQuery" : {
"_id" : {
"$eq" : ObjectId("5ee9b6c125b9a9a426d9965f")
}
},
"winningPlan" : {
"stage" : "IDHACK"
},
"rejectedPlans" : []
},
如我们所见,我们在查询 _id 时有IDHACK。
现在我们结合 _id 和 name:
db.getCollection('users').find({"_id":ObjectId("5ee9b6c125b9a9a426d9965f"), "name":"ana"}).explain("executionStats")
这是结果:
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "anonymous-chat.users",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"_id" : {
"$eq" : ObjectId("5ee9b6c125b9a9a426d9965f")
}
},
{
"name" : {
"$eq" : "ana"
}
}
]
},
"winningPlan" : {
"stage" : "FETCH",
"filter" : {
"name" : {
"$eq" : "ana"
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"_id" : 1
},
"indexName" : "_id_",
"isMultiKey" : false,
"multiKeyPaths" : {
"_id" : []
},
"isUnique" : true,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"_id" : [
"[ObjectId('5ee9b6c125b9a9a426d9965f'), ObjectId('5ee9b6c125b9a9a426d9965f')]"
]
}
}
},
"rejectedPlans" : []
},
如我们所见,索引有助于提高查询性能,因为我们有两个阶段,IXSCAN(索引扫描)和FETCH 阶段,用于过滤最后阶段的文档。
现在让我们查询多个非索引字段以了解您的第二个问题:
db.getCollection('users').find({"name":"ana", "appId":1}).explain("executionStats")
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "anonymous-chat.users",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"appId" : {
"$eq" : 1.0
}
},
{
"name" : {
"$eq" : "ana"
}
}
]
},
"winningPlan" : {
"stage" : "COLLSCAN",
"filter" : {
"$and" : [
{
"appId" : {
"$eq" : 1.0
}
},
{
"name" : {
"$eq" : "ana"
}
}
]
},
"direction" : "forward"
},
"rejectedPlans" : []
},
正如我们在上面看到的,对于多个字段只有一个集合扫描。