我的数据集包含一个包含带整数数组的字段的文档。当我指望其字段包含某个范围内的元素的对象时,索引扫描性能似乎随着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
}
此问题是否有解决方法?
感谢。
答案 0 :(得分: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有关。使用最新的开发版本可能会以稳定为代价来解决问题。