MongoDB 索引不帮助查询多键索引

标签 mongodb performance mongoengine mlab database

我有一个定义了多键索引的文档集合。但是,仅 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"
}

最佳答案

我看到三个因素在起作用。

首先,出于应用目的,请确保 $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 的性质(数组中的子文档中的数组)有关。对于如此高的 nscanned 来说,200 毫秒似乎是合适的。

更高效的文档组织可能是对子文档中的 account_id -> bank_id 关系进行非规范化,并存储:

{"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"
        ]
    ]
    }
}

关于MongoDB 索引不帮助查询多键索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14916749/

相关文章:

python - Mongoengine - 使用 icontains 与所有

java - 在 MySQL 上使用 NoSQL 数据库

mongodb - embedded_in 在 mongoid 中的意义

performance - Apache Benchmark - 随机查询字符串?

python - 操作错误 : Could not save document (LEFT_SUBFIELD only supports Object: ancestors. 0 不是:7)

python - 文档中的 Mongoengine creation_time 属性

javascript - 来自 MLab 的 MongoDB : find by ID not working

ruby - 这是在 Ruby 中保持连接池的首选方法吗

regex - 为什么将代码作为函数调用比直接在 Clozure Common lisp 中调用要花更长的时间?

c# - 泛型与数组列表