0

我的数据集由包含具有整数数组的字段的文档组成。当我指望其字段包含某个范围内的元素的对象时,索引扫描性能似乎随着 indexBounds 值的增加而降低(但该范围扫描的值数量相同)。

测试数据:

for (var i = 0; i < 100000; i++) db.foo.insert({tts:(function(){var val = [];for(var j = 0; j < 100; j++) {val[j] = j} return val;})()});
db.foo.ensureIndex({tts:1});

查询:

> db.foo.find({tts:{$elemMatch:{$gte:10, $lte:10}}}).explain()
{
    "cursor" : "BtreeCursor tts_1",
    "isMultiKey" : true,
    "n" : 100000,
    "nscannedObjects" : 100000,
    "nscanned" : 100000,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 1,
    "nChunkSkips" : 0,
    "millis" : 313,
    "indexBounds" : {
        "tts" : [
            [
                10,
                10
            ]
        ]
    },
    "server" : "localhost:27017"
}
> db.foo.find({tts:{$elemMatch:{$gte:90, $lte:90}}}).explain()
{
    "cursor" : "BtreeCursor tts_1",
    "isMultiKey" : true,
    "n" : 100000,
    "nscannedObjects" : 100000,
    "nscanned" : 100000,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 1,
    "nChunkSkips" : 0,
    "millis" : 1286,
    "indexBounds" : {
        "tts" : [
            [
                90,
                90
            ]
        ]
    },
    "server" : "localhost:27017"
}

事实上,我在这个字段中有近 200 个值,当请求的范围具有最高边界时,查询速度会慢 10 倍。(字段中的每个值都属于一个唯一的范围,所有范围选择相同数量的对象(100000),仅对该范围的子范围进行查询)

收藏统计:

> db.foo.stats()
{
    "ns" : "test.foo",
    "count" : 100000,
    "size" : 122400128,
    "avgObjSize" : 1224.00128,
    "storageSize" : 140763136,
    "numExtents" : 12,
    "nindexes" : 2,
    "lastExtentSize" : 40071168,
    "paddingFactor" : 1,
    "systemFlags" : 1,
    "userFlags" : 0,
    "totalIndexSize" : 254845920,
    "indexSizes" : {
        "_id_" : 3262224,
        "tts_1" : 251583696
    },
    "ok" : 1
}

有解决此问题的方法吗?

谢谢。

4

1 回答 1

0

Mongo 能够使用索引来确定每个文档中是否有一个元素与 $lte 和 $gte 条件匹配。$elemmatch 要求单个元素匹配两个条件,因此 mongo 扫描每个文档(和子数组)以确定是否存在这样的元素。对于较大的值,mongo 必须将 90 个元素扫描到每个数组中,而不是仅扫描前 10 个元素以找到匹配的元素。因此,查询长数组末尾的匹配元素将花费更长的时间。

请注意,如果您反转数组,则行为会反转:

for (var i = 0; i < 100000; i++) db.foo.insert({tts:(function(){var val = [];for(var j = 100; j >= 0; j--) {val[j] = j} return val;})()});

看起来这可能与https://jira.mongodb.org/browse/SERVER-6002有关。使用最新的开发版本可能会以稳定性为代价来解决问题。

于 2012-07-11T05:39:03.477 回答