gpt4 book ai didi

performance - 带排序的 MongoDB 地理空间查询 - 性能问题

转载 作者:可可西里 更新时间:2023-11-01 09:57:30 25 4
gpt4 key购买 nike

我有查询(非常慢 ~2,5s):

db.markers.find({ latlng: { '$within': { '$box': [ [ -16, -140 ], [ 75, 140 ] ] } } }).sort({_id: -1}).limit(1000)

当我为这个查询运行 explain 时,我得到了

{
"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}) explain 给我(快速查询 5 milis):

{
"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 和 compound 索引上有 desc 索引。

db.markers.ensureIndex({latlng: '2d', _id:-1})
db.markers.ensureIndex({ latlng: '2d' })
db.markers.ensureIndex({ _id: -1 })

我想要实现的是从最新排序的特定区域获取标记。

有什么想法或建议可以让时间少于 2.5 秒吗??

如果有人想自己做测试

var i = 0,
lat = 0,
lng = 0;

for (i; i < 260000; i++) {
lat = parseFloat(Math.min(-90 + (Math.random() * 180), 90).toFixed(6));
lng = parseFloat(Math.min(-180 + (Math.random() * 360), 180).toFixed(6));
collection.insert({latlng: [lat, lng]}, function () {});
}

collection.find({ latlng: { '$within': { '$box': [ [ -90, -180 ], [ 90, 180 ] ] } } }, {latlng: 1, _id: 1 }).sort({_id: -1}).limit(1000).explain()

在我的本地机器上,我收到(~ 2,6s):

{
"cursor" : "GeoBrowse-box",
"isMultiKey" : false,
"n" : 1000,
"nscannedObjects" : 260000,
"nscanned" : 260000,
"nscannedObjectsAllPlans" : 260000,
"nscannedAllPlans" : 260000,
"scanAndOrder" : true,
"indexOnly" : false,
"nYields" : 1612,
"nChunkSkips" : 0,
"millis" : 2613,
"indexBounds" : {
"latlng" : [ ]
},
"lookedAt" : NumberLong(260000),
"matchesPerfd" : NumberLong(260000),
"objectsLoaded" : NumberLong(260000),
"pointsLoaded" : NumberLong(0),
"pointsSavedForYield" : NumberLong(0),
"pointsChangedOnYield" : NumberLong(0),
"pointsRemovedOnYield" : NumberLong(0),
"server" : "xx:27017"
}

谢谢

最佳答案

您的集合中是否真的定义了以下三个索引?

db.markers.ensureIndex({ latlng: '2d', _id:-1 })
db.markers.ensureIndex({ latlng: '2d' })
db.markers.ensureIndex({ _id: -1 })

geospatial indexing文档建议不要在同一集合上创建多个地理索引。尽管 MongoDB 允许这样做,但这种行为可能并不理想。我对您的情况的猜测是,可能已选择使用非复合 {latlng: '2d'} 而不是复合索引。 explain() 输出在这里并没有真正帮助我们,因为它只是报告 GeoBrowse-box 而不是索引名称;但是,我会建议手动 hinting游标使用复合索引并查看结果是否有所改善。或者,简单地摆脱非复合索引,所以 {latlng: '2d', _id:-1} 因为查询优化器显而易见且唯一的选择。

最后,{_id: -1} 索引是多余的,可以删除。根据 compound index文档,方向仅在处理由多个字段组成的索引时才相关。对于单键索引,我们可以很容易地向后或向前遍历索引。由于 MongoDB 已经默认为我们创建了一个 {_id: 1} 索引,因此简单地依赖它会更有效。

现在,索引不受影响:查询的一个警告是,在按非地理条件(在您的情况下为 _id)排序之前,限制应用于地理空间查询组件。我相信这意味着,虽然您的结果确实会按 _id 排序,但该排序可能不会考虑匹配范围内的所有文档。 compound index 中提到了这一点文档的一部分,其中引用了 SERVER-4247作为悬而未决的解决方案。


编辑:跟进您的基准

我填充了示例数据,它们是 ±90 到 ±180 之间的 260k 个随机点。然后我运行了您的查询:

db.markers.find(
{ latlng: { $within: { $box: [[-90, -180], [90, 180]] }}},
{ latlng: 1, _id: 1 }
).sort({_id: -1}).limit(1000).explain()

这花费了 1713 毫秒(我将用它作为比较基准,而不是你的 2351 毫秒)。我还会注意到查询匹配了所有 260k 文档,并扫描了相同数量的索引条目。似乎限制在 _id 排序之前没有考虑,这不是我根据注释 here 所期望的。 .然后我稍微调整了查询​​以检查其他一些情况:

  • 没有 _id 排序和限制的原始查询:nscanned 为 260k,时间为 1470ms。
  • 没有 _id 排序的原始查询:nscanned 为 1000,时间为 9ms。
  • 无限制的原始查询:nscanned为260k,时间为2567ms。

我还想单独测试未索引字段的排序,以模拟 _id 排序在地理匹配后可能发生的情况;但是,我无法使用 _id,因为默认索引将始终存在。为此,我删除了复合地理索引,然后按 latlng 对象排序。这导致 260k 的 nscanned 和 1039ms 的时间。如果我加上 1000 的限制,则时间为 461 毫秒。

如果我们将其添加到上面的 1470 毫秒(没有排序和限制的地理查询),它非常接近没有限制的原始查询,即 2567 毫秒。同样,如果我们将 461 毫秒 ( limited sort ) 添加到 1470 毫秒,它接近原始基准测试结果 1713 毫秒。基于这种相关性,我敢打赌您的基准测试中的 _id 排序根本没有利用复合索引。

无论如何,基准测试速度慢的另一个原因是地理匹配范围非常广。更严格的边界肯定会导致更少的数据排序,即使该排序未被索引。也就是说,我确实认为SERVER-4247会对您有所帮助,因为它可能会在执行地理匹配之前先处理非地理排序。

关于performance - 带排序的 MongoDB 地理空间查询 - 性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12908871/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com