我有以下架构:

{
    score  : { type : Number},
    edges : [{name : { type : String }, rank  : { type : Number }}],
    disable : {type : Boolean},
}

我已尝试为以下查询生成索引:
db.test.find( {
    disable: false,
    edges: { $all: [
        { $elemMatch:
            { name: "GOOD" } ,
        },
        { $elemMatch:
            { name: "GREAT" } ,
        },
    ] },
}).sort({"score" : 1})
.limit(40)
.explain()

第一次尝试
当我创建索引名“score”时:
{
    "edges.name" : 1,
    "score" : 1
}

“解释”返回:
{
  "cursor" : "BtreeCursor score",
  ....
}

第二次尝试
当我把“分数”改成:
{
    "disable" :  1,
    "edges.name" : 1,
    "score" : 1
}

“解释”返回:
 "clauses" : [
    {
        "cursor" : "BtreeCursor name",
        "isMultiKey" : true,
        "n" : 0,
        "nscannedObjects" : 304,
        "nscanned" : 304,
        "scanAndOrder" : true,
        "indexOnly" : false,
        "nChunkSkips" : 0,
        "indexBounds" : {
            "edges.name" : [
                [
                    "GOOD",
                    "GOOD"
                ]
            ]
        }
    },
    {
        "cursor" : "BtreeCursor name",
        "isMultiKey" : true,
        "n" : 0,
        "nscannedObjects" : 304,
        "nscanned" : 304,
        "scanAndOrder" : true,
        "indexOnly" : false,
        "nChunkSkips" : 0,
        "indexBounds" : {
            "edges.name" : [
                [
                    "GOOD",
                    "GOOD"
                ]
            ]
        }
    }
],
"cursor" : "QueryOptimizerCursor",
....
}

其中“name”索引为:
{
    'edges.name' : 1
 }

为什么mongo拒绝使用索引中的“disable”字段?
(我也尝试过其他字段,除了“disable”,但遇到了相同的问题)

最佳答案

看起来查询优化程序正在选择最有效的索引,edges.name上的索引最有效。我根据您的模式插入了几个文档,从而重新创建了您的集合。然后我创建了下面的复合索引。

db.test.ensureIndex({
    "disable" :  1,
    "edges.name" : 1,
    "score" : 1
});

对指定的查询运行解释时,使用了索引。
> db.test.find({ ... }).sort({ ... }).explain()
{
    "cursor" : "BtreeCursor disable_1_edges.name_1_score_1",
    "isMultiKey" : true,
    ...
}

但是,当我在edges.name上添加索引时,查询优化程序就为查询选择了该索引。
> db.test.find({ ... }).sort({ ... }).explain()
{
"cursor" : "BtreeCursor edges.name_1",
"isMultiKey" : true,
...
}

但是,如果希望查询使用复合索引,则仍然可以提示其他索引。
> db.test.find({ ... }).sort({ ... }).hint("disable_1_edges.name_1_score_1").explain()
{
    "cursor" : "BtreeCursor disable_1_edges.name_1_score_1",
    "isMultiKey" : true,
    ...
}

[编辑:添加了与使用$all相关的可能解释]
请注意,如果在不使用$all的情况下运行查询,查询优化程序将使用复合索引。
> db.test.find({
        "disable": false,
        "edges": { "$elemMatch": { "name": "GOOD" }}})
    .sort({"score" : 1}).explain();
{
    "cursor" : "BtreeCursor disable_1_edges.name_1_score_1",
    "isMultiKey" : true,
    ...
}

我认为这里的问题是您正在使用$all。正如您在explain字段的结果中看到的,有一些子句,每个子句都与您使用$all搜索的某个值有关。因此查询必须找到每个子句的所有disableedges.name对。我的直觉是,这两次使用复合索引的运行使它比直接查看edges.name然后剔除disable的查询慢。这可能与this问题和this问题有关,您可能需要对此进行研究。

关于mongodb - 未选择Mongo复合指数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28660373/

10-12 16:45