MongoDB嵌入式二级复合索引涵盖了慢查询

时间:2013-04-12 09:40:18

标签: mongodb indexing

我有以下嵌入式二级复合指数:

db.people.ensureIndex({"sources_names.source_id":1,"sources_names.value":1})

这是db.people.getIndexes()的一部分:

{
    "v" : 1,
    "key" : {
        "sources_names.source_id" : 1,
        "sources_names.value" : 1
    },
    "ns" : "diglibtest.people",
    "name" : "sources_names.source_id_1_sources_names.value_1"
}

所以我运行以下索引覆盖的查询:

db.people.find({ "sources_names.source_id": ObjectId('5166d57f7a8f348676000001'), "sources_names.value": "Ulrike Weiland" }, {"sources_names.source_id":1, "sources_names.value":1, "_id":0} ).pretty()
{
    "sources_names" : [
        {
            "value" : "Ulrike Weiland",
            "source_id" : ObjectId("5166d57f7a8f348676000001")
        }
    ]
}

花了大约5秒钟。所以我运行解释:

db.people.find({ "sources_names.source_id": ObjectId('5166d57f7a8f348676000001'), "sources_names.value": "Ulrike Weiland" }, {"sources_names.source_id":1, "sources_names.value":1, "_id":0 }).explain()
{
    "cursor" : "BtreeCursor sources_names.source_id_1_sources_names.value_1",
    "isMultiKey" : true,
    "n" : 1,
    "nscannedObjects" : 1260353,
    "nscanned" : 1260353,
    "nscannedObjectsAllPlans" : 1260353,
    "nscannedAllPlans" : 1260353,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 4,
    "nChunkSkips" : 0,
    "millis" : 4308,
    "indexBounds" : {
        "sources_names.source_id" : [
            [
                ObjectId("5166d57f7a8f348676000001"),
                ObjectId("5166d57f7a8f348676000001")
            ]
        ],
        "sources_names.value" : [
            [
                {
                    "$minElement" : 1
                },
                {
                    "$maxElement" : 1
                }
            ]
        ]
    },
    "server" : "dash-pc.local:27017"
}

但为什么这个索引覆盖的查询遍历整个数据库?我应该如何创建索引以提高性能?

谢谢!

1 个答案:

答案 0 :(得分:0)

您正在多个位置使用多键索引(即sources_names.source_id),来自文档(http://docs.mongodb.org/manual/tutorial/create-indexes-to-support-queries/#create-indexes-that-support-covered-queries):

  

如果符合以下情况,索引无法覆盖查询:

     

集合中任何文档中的任何索引字段都包含一个数组。   如果索引字段是数组,则索引将成为多键索引索引,但不能   支持覆盖查询。

你可以在这里说明这是一个多键索引:

"isMultiKey" : true,

基本上点符号被归类为多键,因为sources_names是一个数组,因此索引包含一个数组。

至于提高速度:我没有看过这个,但你的问题在这里:

"sources_names.value" : [
    [
        {
            "$minElement" : 1
        },
        {
            "$maxElement" : 1
        }
    ]
]

因此索引没有被最佳地用于查找sources_names.value

修改

我认为我刚给出的答案有点奇怪,因为这不应该是一个多键索引,所以我实际上已经测试了这个:

> db.gh.ensureIndex({'d.id':1,'d.g':1})
> db.gh.find({'d.id':5, 'd.g':'d'})
{ "_id" : ObjectId("516826e5f44947064473a00a"), "d" : { "id" : 5, "g" : "d" } }
> db.gh.find({'d.id':5, 'd.g':'d'}).explain()
{
        "cursor" : "BtreeCursor d.id_1_d.g_1",
        "isMultiKey" : false,
        "n" : 1,
        "nscannedObjects" : 1,
        "nscanned" : 1,
        "nscannedObjectsAllPlans" : 1,
        "nscannedAllPlans" : 1,
        "scanAndOrder" : false,
        "indexOnly" : false,
        "nYields" : 0,
        "nChunkSkips" : 0,
        "millis" : 0,
        "indexBounds" : {
                "d.id" : [
                        [
                                5,
                                5
                        ]
                ],
                "d.g" : [
                        [
                                "d",
                                "d"
                        ]
                ]
        },
        "server" : "ubuntu:27017"
}

似乎我原来的想法在哪里,这不应该是一个多键索引。你在value认为有一些脏数据,这会导致你出现问题。

我会查看您的数据库并确保正确输入您的记录。

你很可能有类似的东西:

{
    "sources_names" : [
        {
            "value" : ["Ulrike Weiland", 1],
            "source_id" : ObjectId("5166d57f7a8f348676000001")
        }
    ]
}

有些地方。