Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance 使用$all和$elemMatch时,MongoDB会扫描整个索引_Performance_Mongodb_Indexing - Fatal编程技术网

Performance 使用$all和$elemMatch时,MongoDB会扫描整个索引

Performance 使用$all和$elemMatch时,MongoDB会扫描整个索引,performance,mongodb,indexing,Performance,Mongodb,Indexing,我有一个用户文档集合,其中每个用户都可以拥有任意一组属性。每个用户都关联到一个应用程序文档。以下是一个示例用户: { "appId": "XXXXXXX", "properties": [ { "name": "age", "value": 30 }, { "name": "gender", "value": "female" }, { "name": "alive", "value": true } ] } 我希望能够根

我有一个用户文档集合,其中每个用户都可以拥有任意一组属性。每个用户都关联到一个应用程序文档。以下是一个示例用户:

{
    "appId": "XXXXXXX",
    "properties": [
        { "name": "age", "value": 30 },
        { "name": "gender", "value": "female" },
        { "name": "alive", "value": true }
    ]
}
我希望能够根据用户属性的值查找/统计用户。例如,查找属性Y>10且Z等于true的应用程序X的所有用户

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

db.users.find({
    appId: 'XXXXXX',
    properties: {
        $elemMatch: {
            name: 'age',
            value: {
                $gt: 10
            }
        }
    }
})
上述查询在小于300毫秒的时间内完成,收集了100万用户。但是,当我尝试添加第二个条件时,性能会显著降低(7-8秒),并且
explain()
输出指示正在扫描整个索引以完成查询(
“nscaned”:2752228

质疑

说明

{
    "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不适合这种类型的用例?

我知道这是一个老问题,但我认为最好不要使用“名称”和“值”标记来构造数据:


您使用的是MongoDB的2.6版本,对吗?我无法重现这种情况-在3.0-rc8中,查询速度很快,即它不会扫描对象。@mnemosyn是的,我使用的是v2.6.7。也许3.0-rc8可以解决您的问题?至少如果你愿意在生产中使用一个候选发布版本……不幸的是,我认为在3.0正式发布之前,这不是一个选项,因为我们的数据库托管在云端。是的,这种行为预计<3.0。在3.0版本发布后升级将对您有所帮助,因为查询计划已经改进,能够处理这种情况。您真的需要这样的元数据数组吗?如果您能提供帮助的话,这将有助于您现在拥有一个更标准的文档结构。对于我们的用例,这是不可能的,因为我们无法提前知道密钥-它们是用户生成的,并且它们都需要索引/可查询。
{
    "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
}
{
    "appId": "XXXXXXX",
    "properties": [
        { "age": 30 },
        { "gender: "female" },
        { "alive": true }
                   ]
}