我有一组定义了多键索引的文档。但是,对于43K文档,查询的性能相当差。这个查询的〜215ms被认为是差的吗?如果nscanned是43902(等于集合中的文档总数),我是否正确定义了索引?
文件:
{
"_id": {
"$oid": "50f7c95b31e4920008dc75dc"
},
"bank_accounts": [
{
"bank_id": {
"$oid": "50f7c95a31e4920009b5fc5d"
},
"account_id": [
"ff39089358c1e7bcb880d093e70eafdd",
"adaec507c755d6e6cf2984a5a897f1e2"
]
}
],
"created_date": "2013,01,17,09,50,19,274089",
}
指数:
{ "bank_accounts.bank_id" : 1 , "bank_accounts.account_id" : 1}
查询:
db.visitor.find({ "bank_accounts.account_id" : "ff39089358c1e7bcb880d093e70eafdd" , "bank_accounts.bank_id" : ObjectId("50f7c95a31e4920009b5fc5d")}).explain()
说明:
{
"cursor" : "BtreeCursor bank_accounts.bank_id_1_bank_accounts.account_id_1",
"isMultiKey" : true,
"n" : 1,
"nscannedObjects" : 43902,
"nscanned" : 43902,
"nscannedObjectsAllPlans" : 43902,
"nscannedAllPlans" : 43902,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 213,
"indexBounds" : {
"bank_accounts.bank_id" : [
[
ObjectId("50f7c95a31e4920009b5fc5d"),
ObjectId("50f7c95a31e4920009b5fc5d")
]
],
"bank_accounts.account_id" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
},
"server" : "Not_Important"
}
答案 0 :(得分:8)
我发现有三个因素在起作用。
首先,出于应用目的,请确保$ elemMatch对于此用例不是更合适的查询。 http://docs.mongodb.org/manual/reference/operator/elemMatch/。如果由于多个子文档满足查询而返回错误结果似乎会很糟糕。
其次,我想通过独立查询每个字段值可以解决高nscanned值。 .find({bank_accounts.bank_id:X})与.find({“bank_accounts.account_id”:Y})。您可能会看到完整查询的nscanned大约等于最大子查询的nscanned。如果索引键被完全作为范围进行评估,则不会出现这种情况,但是......
第三,解释计划的{“bank_accounts.account_id”:[[{“$ minElement”:1},{“$ maxElement”:1}]]}子句显示没有范围应用于此部分关键。
不确定原因,但我怀疑它与account_id的性质(数组中的子文档中的数组)有关。 200毫秒似乎适合nscan高。
更高效的文档组织可能是对account_id进行非规范化 - >子文档中的bank_id关系,以及store:
{"bank_accounts": [
{
"bank_id": X,
"account_id: Y,
},
{
"bank_id": X,
"account_id: Z,
}
]}
代替: {“银行账户”: [{ “bank_id”:X, “account_id:[Y,Z], }]}
下面的测试表明,使用此组织,查询优化器可以恢复工作并在两个密钥上施加范围:
> db.accounts.insert({"something": true, "blah": [{ a: "1", b: "2"} ] })
> db.accounts.ensureIndex({"blah.a": 1, "blah.b": 1})
> db.accounts.find({"blah.a": 1, "blah.b": "A RANGE"}).explain()
{
"cursor" : "BtreeCursor blah.a_1_blah.b_1",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 0,
"nscanned" : 0,
"nscannedObjectsAllPlans" : 0,
"nscannedAllPlans" : 0,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"blah.a" : [
[
1,
1
]
],
"blah.b" : [
[
"A RANGE",
"A RANGE"
]
]
}
}