【问题标题】:Mongo DB - Slower With IndexMongodb - 索引变慢
【发布时间】:2014-07-12 16:28:12
【问题描述】:

我在一个集合中有大约 1000000 个文档(随机生成)。

示例文档:

{
    "loc": {
        "lat": 39.828475,
        "lon": 116.273542
    },
    "phone": "",
    "keywords": [
        "big",
        "small",
        "biggest",
        "smallest"
    ],
    "prices": [
        {
            "category": "uRgpiamOVTEQ",
            "list": [
                {
                    "price": 29,
                    "name": "ehLYoPpntlil"
                }
            ]
        },
        {
            "category": "ozQNmdwpwhXPnabZ",
            "list": [
                {
                    "price": 96,
                    "name": "ITTaLHf"
                },
                {
                    "price": 88,
                    "name": "MXVgJFBgtwLYk"
                }
            ]
        },
        {
            "category": "EDkfKGZSou",
            "list": [
                {
                    "price": 86,
                    "name": "JluoCLnenOqDllaEX"
                },
                {
                    "price": 35,
                    "name": "HbmgMDfxCOk"
                },
                {
                    "price": 164,
                    "name": "BlrUD"
                },
                {
                    "price": 106,
                    "name": "LOUcsMDeaqVm"
                },
                {
                    "price": 14,
                    "name": "rDkwhN"
                }
            ]
        }
    ],
}

无索引搜索

> db.test1.find({"prices.list.price": { $gt: 190 } }).explain()
{
    "cursor" : "BasicCursor",
    "isMultiKey" : false,
    "n" : 541098,
    "nscannedObjects" : 1005584,
    "nscanned" : 1005584,
    "nscannedObjectsAllPlans" : 1005584,
    "nscannedAllPlans" : 1005584,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 8115,
    "nChunkSkips" : 0,
    **"millis" : 13803,**
    "server" : "localhost:27017",
    "filterSet" : false
}

有索引:

> db.test1.ensureIndex({"prices.list.price":1,"menu.list.name":1})
{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
}

> db.test1.find({"prices.list.price": { $gt: 190 } }).explain()
{
    "cursor" : "BtreeCursor prices.list.price_1_prices.list.name_1",
    "isMultiKey" : true,
    "n" : 541098,
    "nscannedObjects" : 541098,
    "nscanned" : 868547,
    "nscannedObjectsAllPlans" : 541098,
    "nscannedAllPlans" : 868547,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 16852,
    "nChunkSkips" : 0,
    **"millis" : 66227,**
    "indexBounds" : {
        "menu.list.price" : [
            [
                190,
                Infinity
            ]
        ],
        "menu.list.name" : [
            [
                {
                    "$minElement" : 1
                },
                {
                    "$maxElement" : 1
                }
            ]
        ]
    },
    "server" : "localhost:27017",
    "filterSet" : false
}

知道为什么索引搜索比没有索引慢吗?

我也会使用:

db.test1.find( { loc : { $near : [39.876045, 32.862245]}}) (需要二维索引)

db.test1.find({ keywords:{$in: [ "small", "another" ] }}) (对关键字使用索引)

db.test1.find({"prices.list.name":/.s./ }) (不需要索引,因为我将使用正则表达式)

【问题讨论】:

    标签: mongodb indexing


    【解决方案1】:

    索引允许更快地访问满足查询的文档位置。

    在您的示例中,您的查询选择了集合中所有文档的一半。因此,即使索引扫描提供了更快的访问来了解哪些文档将匹配查询谓词,但它实际上总体上会产生更多的工作。

    在集合扫描中,查询正在扫描所有文档,并检查您查询的字段是否匹配。有一半的时间最终选择了文档。

    在索引扫描中,查询是遍历所有索引条目的一半,然后从它们直接跳转到满足查询谓词的文档。在你的情况下,这就是更多的操作。

    此外,在执行此操作时,当操作需要等待他们必须读取的文档被带入 RAM 时,或者当有一个正在等待执行的写入时,操作会产生读取互斥锁,并且索引scan 显示的产量数量是收集扫描的两倍。如果您的工作集没有足够的 RAM,那么添加索引会给现有资源带来更多压力,并使事情变得更慢,而不是更快。

    与更大的数字(例如 500 或任何在您的数据集中更具选择性的数字)相比,尝试使用价格进行相同的查询。如果使用索引查询仍然较慢,那么您可能会在系统上看到很多页面错误。但是,如果有足够的 RAM 用于索引,则索引查询会快很多,而未索引查询会同样慢。

    【讨论】:

    • 很好的解释@asya。在那种情况下,为什么 mongo 使用索引而不是使用没有索引的替代计划?
    【解决方案2】:

    首先,作为一项建议,您在使用 elemMatch 查询数组时会变得更快。 http://docs.mongodb.org/manual/reference/operator/query/elemMatch/ 你的情况

    db.test1.find({"prices.list.price":{ $elemMatch: { $gte: 190 }}  })
    

    第二件事是

    为索引包含数组值的字段,MongoDB 添加索引项 对于数组中的每个项目。这些多键索引允许 MongoDB 使用数组的值从查询中返回文档。 MongoDB 自动判断是否创建多键索引,如果 索引字段包含一个数组值;你不需要明确 指定多键类型。

    考虑下面的多键索引图示:

    addr.zip 字段上的多键索引图。 addr 字段包含一个数组 地址文件。地址文件包含 zip 字段。

    多键索引支持其他 MongoDB 支持的所有操作 索引;但是,应用程序可以使用多键索引来选择 基于数组值的值范围的文档。 多键索引支持同时保存两个值的数组(例如字符串、 数字)和嵌套文档。

    来自http://docs.mongodb.org/manual/core/index-multikey/

    【讨论】:

    • $elemMatch 确实 not 使查询更快,当您匹配单个数组元素中的多个字段时,它会使它们更“正确”。无论如何,查询速度较慢的原因不是多键索引,而是它不是一个非常有选择性的查询。
    猜你喜欢
    • 2015-10-22
    • 2014-07-12
    • 1970-01-01
    • 1970-01-01
    • 2019-02-10
    • 2015-05-19
    • 1970-01-01
    • 1970-01-01
    • 2016-07-10
    相关资源
    最近更新 更多