我有查询(这很慢~2,5s):
db.markers.find({ latlng: { '$within': { '$box': [ [ -16, -140 ], [ 75, 140 ] ] } } }).sort({_id: -1}).limit(1000)
当我对此查询运行解释时,我得到
{
"cursor" : "GeoBrowse-box",
"isMultiKey" : false,
"n" : 1000,
"nscannedObjects" : 242331,
"nscanned" : 242331,
"nscannedObjectsAllPlans" : 242331,
"nscannedAllPlans" : 242331,
"scanAndOrder" : true,
"indexOnly" : false,
"nYields" : 1383,
"nChunkSkips" : 0,
"millis" : 2351,
"indexBounds" : {
"latlng" : [ ]
},
"lookedAt" : NumberLong(262221),
"matchesPerfd" : NumberLong(242331),
"objectsLoaded" : NumberLong(242331),
"pointsLoaded" : NumberLong(0),
"pointsSavedForYield" : NumberLong(0),
"pointsChangedOnYield" : NumberLong(0),
"pointsRemovedOnYield" : NumberLong(0),
"server" : "xx:27017"
}
当我删除sort({_id: -1})时,解释给了我(快速查询5 毫秒):
{
"cursor" : "GeoBrowse-box",
"isMultiKey" : false,
"n" : 1000,
"nscannedObjects" : 1000,
"nscanned" : 1000,
"nscannedObjectsAllPlans" : 1000,
"nscannedAllPlans" : 1000,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 5,
"indexBounds" : {
"latlng" : [ ]
},
"lookedAt" : NumberLong(1000),
"matchesPerfd" : NumberLong(1000),
"objectsLoaded" : NumberLong(1000),
"pointsLoaded" : NumberLong(0),
"pointsSavedForYield" : NumberLong(0),
"pointsChangedOnYield" : NumberLong(0),
"pointsRemovedOnYield" : NumberLong(0),
"server" : "xx:27017"
}
我在 latlng 上有 2d 索引,在 _id 上有 desc 索引和复合索引。
db.markers.ensureIndex({latlng: '2d', _id:-1})
db.markers.ensureIndex({ latlng: '2d' })
db.markers.ensureIndex({ _id: -1 })
我想要实现的是从最新排序的特定区域获取标记。
任何想法或建议如何在不到2.5 秒的时间内做到这一点?
MongoDB 中的查询一次只能使用一个索引,因此只能使用一个索引 - 它不能先使用 2d 索引,然后对 _id 索引进行排序。为了对选择和排序都使用索引,您需要一个像这样的复合索引:
试试这个,或者类似的,看看它如何影响结果,记住一旦你定义了它,你可以删除原始的 2d 索引以节省空间,并且这个新索引必须加载到内存中才能有效。
更新:正如摘要中提到的,上述并没有改善事情,结果查询结果是 scanAndOrder 结果。这也发生在基于范围的查询中,正如这篇优秀的博客文章中所解释的:
http://blog.mongolab.com/2012/06/cardinal-ins/
如该帖子所述,基于范围的查询性能的通常解决方案是切换索引的顺序。然而,目前这对于地理索引是不可能的。这里已经有一个 Jira 问题可供投票和跟踪:
https://jira.mongodb.org/browse/SERVER-4247