mongodb - 未选择 Mongo 复合索引

标签 mongodb indexing

我有以下架构:

{
    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",
....
}

“名称”索引在哪里:

{
    'edges.name' : 1
 }

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

最佳答案

看起来查询优化器正在选择最有效的索引,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。正如您在解释字段的结果中看到的那样,有一些子句,每个子句都与您使用 $all 搜索的值之一有关。因此,查询必须为每个子句找到所有 disableedges.name 对。我的直觉是,这两次使用复合索引运行比直接查看 edges.name 然后清除 disable 的查询慢。这可能与 this 有关问题和this问题,您可能想调查一下。

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

相关文章:

python - 如何将大量数据附加到 Pandas HDFStore 并获得自然的唯一索引?

python - 处理 Tkinter 文本小部件索引系统。

mongodb - 如果不存在如何在 Mongoose 中创建但不更新

mongodb - 有人用过 Aerospike 吗?它与 MongoDB 相比如何?

node.js - Mongoose 中的自动递增序列

尝试使用 list.insert 时出现 Python 索引错误

c++ - 查找 blob 中最长的 blob 前缀

python - Pandas 将列变成 MultiIndex

mongodb - mongodb 中的数组过滤器

MongoDB 设计 - 大型嵌套文档,还是拆分成多个集合?