gpt4 book ai didi

MongoDB 2dsphere 索引 $geoWithin 性能

转载 作者:IT老高 更新时间:2023-10-28 13:08:44 27 4
gpt4 key购买 nike

我有一个 GeoJSON Point 形式的坐标数据集合,我需要从中查询一个区域内的 10 个最新条目。现在有 1.000.000 个条目,但将增加大约 10 倍。

我的问题是,当所需区域内有很多条目时,我的查询性能会大大下降(案例 3)。我目前拥有的测试数据是随机的,但真实数据不会,因此无法仅根据区域的尺寸选择另一个索引(如案例 4)。

我应该怎么做才能让它无论在哪个区域都能按预期执行?

1.收集统计:

> db.randomcoordinates.stats()
{
"ns" : "test.randomcoordinates",
"count" : 1000000,
"size" : 224000000,
"avgObjSize" : 224,
"storageSize" : 315006976,
"numExtents" : 15,
"nindexes" : 3,
"lastExtentSize" : 84426752,
"paddingFactor" : 1,
"systemFlags" : 0,
"userFlags" : 0,
"totalIndexSize" : 120416128,
"indexSizes" : {
"_id_" : 32458720,
"position_2dsphere_timestamp_-1" : 55629504,
"timestamp_-1" : 32327904
},
"ok" : 1
}

<强>2。索引:

> db.randomcoordinates.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "test.randomcoordinates",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"position" : "2dsphere",
"timestamp" : -1
},
"ns" : "test.randomcoordinates",
"name" : "position_2dsphere_timestamp_-1"
},
{
"v" : 1,
"key" : {
"timestamp" : -1
},
"ns" : "test.randomcoordinates",
"name" : "timestamp_-1"
}
]

3.使用 2dsphere 复合索引查找:

> db.randomcoordinates.find({position: {$geoWithin: {$geometry: {type: "Polygon", coordinates: [[[1, 1], [1, 90], [180, 90], [180, 1], [1, 1]]]}}}}).sort({timestamp: -1}).limit(10).hint("position_2dsphere_timestamp_-1").explain()
{
"cursor" : "S2Cursor",
"isMultiKey" : true,
"n" : 10,
"nscannedObjects" : 116775,
"nscanned" : 283424,
"nscannedObjectsAllPlans" : 116775,
"nscannedAllPlans" : 283424,
"scanAndOrder" : true,
"indexOnly" : false,
"nYields" : 4,
"nChunkSkips" : 0,
"millis" : 3876,
"indexBounds" : {

},
"nscanned" : 283424,
"matchTested" : NumberLong(166649),
"geoTested" : NumberLong(166649),
"cellsInCover" : NumberLong(14),
"server" : "chan:27017"
}

4.使用时间戳索引查找:

> db.randomcoordinates.find({position: {$geoWithin: {$geometry: {type: "Polygon", coordinates: [[[1, 1], [1, 90], [180, 90], [180, 1], [1, 1]]]}}}}).sort({timestamp: -1}).limit(10).hint("timestamp_-1").explain()
{
"cursor" : "BtreeCursor timestamp_-1",
"isMultiKey" : false,
"n" : 10,
"nscannedObjects" : 63,
"nscanned" : 63,
"nscannedObjectsAllPlans" : 63,
"nscannedAllPlans" : 63,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"timestamp" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
]
},
"server" : "chan:27017"
}

有人建议使用 {timestamp: -1, position: "2dsphere"} 索引,所以我也尝试过,但似乎效果不够好。

5.使用 Timestamp + 2dsphere 复合索引查找

> db.randomcoordinates.find({position: {$geoWithin: {$geometry: {type: "Polygon", coordinates: [[[1, 1], [1, 90], [180, 90], [180, 1], [1, 1]]]}}}}).sort({timestamp: -1}).limit(10).hint("timestamp_-1_position_2dsphere").explain()
{
"cursor" : "S2Cursor",
"isMultiKey" : true,
"n" : 10,
"nscannedObjects" : 116953,
"nscanned" : 286513,
"nscannedObjectsAllPlans" : 116953,
"nscannedAllPlans" : 286513,
"scanAndOrder" : true,
"indexOnly" : false,
"nYields" : 4,
"nChunkSkips" : 0,
"millis" : 4597,
"indexBounds" : {

},
"nscanned" : 286513,
"matchTested" : NumberLong(169560),
"geoTested" : NumberLong(169560),
"cellsInCover" : NumberLong(14),
"server" : "chan:27017"
}

最佳答案

我在寻找类似问题的解决方案时看到了这个问题。这是一个非常古老的问题没有得到解答,如果其他人正在寻找解决此类情况的方法,我将尝试解释为什么提到的方法不适合手头的任务以及如何微调这些查询。

在第一种情况下,扫描这么多项目是完全正常的。让我试着解释一下原因:

当 Mongodb 构建复合索引 "position_2dsphere_timestamp_-1" 时,它实际上创建了一个 B-tree 来保存位置键中包含的所有几何图形,在本例中为点,并且对于每一个如果在这个 B-tree 中存在不同的值,则会创建另一个 B-tree 来按降序保存时间戳。这意味着,除非您的条目非常(我的意思是)彼此非常接近,否则二级 B 树将只保存一个条目,并且查询性能几乎与仅在位置字段上具有索引相同。除了 mongodb 将能够使用辅助 b 树上的时间戳值,而不是将实际文档放入内存并检查时间戳。

当我们构建复合索引“timestamp_-1_position_2dsphere”时,这同样适用于其他场景。以毫秒精度同时输入两个条目是不太可能的。所以在这种情况下;是的,我们的数据按时间戳字段排序,但是我们有许多其他 B 树只为每个不同的时间戳值保存一个条目。因此,应用 geoWithin 过滤器的效果不会很好,因为它必须检查每个条目,直到达到限制。

那么如何才能使这类查询表现良好呢?就我个人而言,我首先在地理空间字段前面放置尽可能多的字段。但主要的技巧是保存另一个字段让我们说“createdDay”,它将保存一个精确到天的数字。如果您需要更高的精度,您也可以使用小时级别的精度,但会以性能为代价,这完全取决于您项目的需求。您的索引将如下所示:{createdDay:-1, position: "2dsphere"}。现在,在同一天创建的每个文档都将在同一个 2dsphere b-tree 索引上存储和排序。所以mongodb会从当天开始,因为它应该是索引中的最大值,并且对createdDay是今天的文档的b-tree持有位置进行索引扫描。如果它找到至少 10 个文档,它将停止并返回这些文档,否则它将移至前一天,依此类推。在您的情况下,这种方法应该会大大提高性能。

我希望这对你的情况有所帮助。

关于MongoDB 2dsphere 索引 $geoWithin 性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18759302/

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