我对mongodb
的查询是:
db.records.find({ from_4: { '$lte': 7495 }, to_4: { '$gte': 7495 } }).sort({ from_11: 1 }).skip(60000).limit(100).hint("from_4_1_to_4_-1_from_11_1").explain()
我建议它应该使用索引from_4_1_to_4_-1_from_11_1
{
"from_4": 1,
"to_4": -1,
"from_11": 1
}
但得到了错误:
error: {
"$err" : "Runner error: Overflow sort stage buffered data usage of 33555322 bytes exceeds internal limit of 33554432 bytes",
"code" : 17144
} at src/mongo/shell/query.js:131
如何避免此错误?
也许我应该创建另一个索引,更符合我的查询。
我也尝试使用所有升序字段编制索引...
{
"from_4": 1,
"to_4": 1,
"from_11": 1
}
......但是同样的错误。
P.S。我注意到,当我删除跳过命令时...
> db.records.find({ from_4: { '$lte': 7495 }, to_4: { '$gte': 7495 } }).sort({ from_11: 1 }).limit(100).hint("from_4_1_to_4_-1_from_11_1").explain()
...没关系,我得到了解释输出,但它说我不使用索引:"indexOnly" : false
{
"clauses" : [
{
"cursor" : "BtreeCursor from_4_1_to_4_-1_from_11_1",
"isMultiKey" : false,
"n" : 100,
"nscannedObjects" : 61868,
"nscanned" : 61918,
"scanAndOrder" : true,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"from_4" : [
[
-Infinity,
7495
]
],
"to_4" : [
[
Infinity,
7495
]
],
"from_11" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
}
},
{
"cursor" : "BtreeCursor ",
"isMultiKey" : false,
"n" : 0,
"nscannedObjects" : 0,
"nscanned" : 0,
"scanAndOrder" : true,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"from_4" : [
[
-Infinity,
7495
]
],
"to_4" : [
[
Infinity,
7495
]
],
"from_11" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
}
}
],
"cursor" : "QueryOptimizerCursor",
"n" : 100,
"nscannedObjects" : 61868,
"nscanned" : 61918,
"nscannedObjectsAllPlans" : 61868,
"nscannedAllPlans" : 61918,
"scanAndOrder" : false,
"nYields" : 832,
"nChunkSkips" : 0,
"millis" : 508,
"server" : "myMac:27026",
"filterSet" : false
}
P.P.S 我看过mongo db tutorial about sort indexes并认为我做得很好。
累积 @dark_shadow 建议我创建了两个以上的索引:
db.records.ensureIndex({from_11: 1})
db.records.ensureIndex({from_11: 1, from_4: 1, to_4: 1})
和索引db.records.ensureIndex({from_11: 1})
成为我的需要:
db.records.find({ from_4: { '$lte': 7495 }, to_4: { '$gte': 7495 } }).sort({ from_11: 1 }).skip(60000).limit(100).explain()
{
"cursor" : "BtreeCursor from_11_1",
"isMultiKey" : false,
"n" : 100,
"nscannedObjects" : 90154,
"nscanned" : 90155,
"nscannedObjectsAllPlans" : 164328,
"nscannedAllPlans" : 164431,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 1284,
"nChunkSkips" : 0,
"millis" : 965,
"indexBounds" : {
"from_11" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
},
"server" : "myMac:27025",
"filterSet" : false
}
答案 0 :(得分:3)
当您使用范围查询(并且您)时,mongo查询无论如何都不要使用索引进行排序。您可以通过查看" scanAndOrder"来检查这一点。测试查询后,您的explain()的值。如果该值存在且为true,则表示它将结果集排序在内存中(扫描和顺序),而不是直接使用索引。这就是您在第一个查询中收到错误的原因。
正如Mongodb文档所说,
对于不使用索引的内存中排序,sort()操作明显变慢。 sort()操作将在使用32兆字节的内存时中止。
您可以在内存排序中使用limit(100)来检查第一个查询中scanAndOrder的值。
您的第二个查询有效,因为您已经使用了限制,因此它只能对100个可以在内存中完成的文档进行排序。
为什么" indexOnly" :false ?
这只是表明您希望返回的所有字段都不在索引中,BtreeCursor表示索引用于查询(BasicCursor意味着它没有)。要使其成为indexOnly查询,您需要在投影中仅返回索引中的那些字段(即:{_ id:0,from_4:1,to_4:1,from_11:1})。这意味着它永远不会触及数据本身,只能从索引中返回您需要的所有内容。一旦修改了查询以仅返回提到的字段,您也可以使用说明进行检查。
现在,你会感到困惑。它是否使用索引?对于排序,它不会使用索引,但是查询它是使用索引。这就是你获得BtreeCusrsor的原因(你应该也看到了你的索引名称)。
现在,要解决您的问题,您可以创建两个索引:
{
"from_4": 1,
"to_4": 1,
}
{
"from_11" : 1
}
然后通过仔细观察scanOrder值来查看它现在是否给出错误或使用索引进行排序。
还有一项工作: 更改compund索引的顺序:
{
"FROM_11" : 1,
"from_4": 1,
"to_4": 1,
}
不确定这种方法。它应该有希望。
看看你想要得到什么,你也可以用{from_11:-1} .limit(1868)进行排序。
我希望我现在能让事情变得更加清晰。请根据我的建议做一些测试。如果您遇到任何问题,请告诉我。我们可以继续努力。
由于