【问题标题】:MongoDB scans entire index when using $all and $elemMatchMongoDB 在使用 $all 和 $elemMatch 时扫描整个索引
【发布时间】:2015-04-21 01:02:21
【问题描述】:

我有一组用户文档,其中每个用户都可以拥有一组任意属性。每个用户都与一个应用文档相关联。这是一个示例用户:

{
    "appId": "XXXXXXX",
    "properties": [
        { "name": "age", "value": 30 },
        { "name": "gender", "value": "female" },
        { "name": "alive", "value": true }
    ]
}

我希望能够根据用户属性的值来查找/计算用户。例如,找到应用 X 的所有属性 Y > 10 且 Z 等于 true 的用户。

我在这个集合db.users.ensureIndex({ "appId": 1, "properties.name": 1, "properties.value": 1}) 上有一个复合多键索引。该索引适用于单条件查询,例如:

db.users.find({
    appId: 'XXXXXX',
    properties: {
        $elemMatch: {
            name: 'age',
            value: {
                $gt: 10
            }
        }
    }
})

上述查询在 explain() 输出表明正在扫描整个索引以完成查询("nscanned" : 2752228)。

查询

db.users.find({
    appId: 'XXXXXX',
    properties: {
        $all: [
            {
                $elemMatch: {
                    name: 'age',
                    value: {
                        $gt: 10
                    }
                }
            },
            {
                $elemMatch: {
                    name: 'alive',
                    value: true
                }
            }
        ]
    }
})

解释

{
    "cursor" : "BtreeCursor appId_1_properties.name_1_properties.value_1",
    "isMultiKey" : true,
    "n" : 256,
    "nscannedObjects" : 1000000,
    "nscanned" : 2752228,
    "nscannedObjectsAllPlans" : 1018802,
    "nscannedAllPlans" : 2771030,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 21648,
    "nChunkSkips" : 0,
    "millis" : 7425,
    "indexBounds" : {
        "appId" : [
            [
                "XXXXX",
                "XXXXX"
            ]
        ],
        "properties.name" : [
            [
                {
                    "$minElement" : 1
                },
                {
                    "$maxElement" : 1
                }
            ]
        ],
        "properties.value" : [
            [
                {
                    "$minElement" : 1
                },
                {
                    "$maxElement" : 1
                }
            ]
        ]
    },
    "filterSet" : false
}

我认为这是因为 Mongo 无法创建合适的边界,因为我正在寻找布尔值和整数值。

我的问题是:有没有更好的方法来构建我的数据,或者修改我的查询以提高性能并更好地利用我的索引?是否可以指示 mongo 分别处理每个条件,生成适当的边界,然后执行结果的交集,而不是扫描所有文档?还是 mongo 不适合这种类型的用例?

【问题讨论】:

  • 您使用的是 2.6 版本的 MongoDB,对吧?我无法重现这一点 - 在 3.0-rc8 中,查询速度很快,即它不扫描对象。
  • @mnemosyn 是的,我使用的是 v2.6.7
  • 嗯,也许 3.0-rc8 可以解决你的问题?至少如果您愿意在生产环境中使用候选版本...
  • 不幸的是,在 3.0 正式发布之前,我认为这不是一个选择,因为我们的数据库托管在云中
  • 是的,对于

标签: performance mongodb indexing


【解决方案1】:

我知道这是一个老问题,但我认为在没有“名称”和“值”标签的情况下构建数据会更好:

{
    "appId": "XXXXXXX",
    "properties": [
        { "age": 30 },
        { "gender: "female" },
        { "alive": true }
                   ]
}

【讨论】:

  • 对于我们的用例来说不可能,因为我们不提前知道键 - 它们是用户生成的,它们都需要被索引/可查询。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-29
  • 2019-08-26
  • 2011-06-28
  • 2012-01-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多