Mongodb 在mongo中搜索范围
当输入数据为单个值且采集数据包含最小/最大范围时,在Mongo中查找数据的最有效方法是什么?例如:Mongodb 在mongo中搜索范围,mongodb,optimization,database,Mongodb,Optimization,Database,当输入数据为单个值且采集数据包含最小/最大范围时,在Mongo中查找数据的最有效方法是什么?例如: record = { min: number, max: number, payload } 需要找到一条记录,该记录的数字在该记录的最小/最大范围内。这些范围从不相交。范围的大小是不可预测的 该收藏中有约600万条记录。如果我解包范围(对范围中的每个值都有记录),我将看到大约4B条记录 我已经创建了{min:1,max:1}的复合索引,但尝试使用以下方法进行搜索: db.block.find(
record = { min: number, max: number, payload }
需要找到一条记录,该记录的数字在该记录的最小/最大范围内。这些范围从不相交。范围的大小是不可预测的
该收藏中有约600万条记录。如果我解包范围(对范围中的每个值都有记录),我将看到大约4B条记录
我已经创建了{min:1,max:1}
的复合索引,但尝试使用以下方法进行搜索:
db.block.find({min:{$lte:value},max:{$gte:value})
。。。需要几秒到几十秒的时间。下面是explain()
和getindex()
的输出。有什么技巧可以让搜索执行得更快吗
NJmongo:PRIMARY> db.block.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "mispot.block",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"min" : 1,
"max" : 1
},
"ns" : "mispot.block",
"name" : "min_1_max_1"
}
]
NJmongo:PRIMARY> db.block.find({max:{$gte:1135194602},min:{$lte:1135194602}}).explain()
{
"cursor" : "BtreeCursor min_1_max_1",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 1199049,
"nscannedObjectsAllPlans" : 1199050,
"nscannedAllPlans" : 2398098,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 7534,
"nChunkSkips" : 0,
"millis" : 5060,
"indexBounds" : {
"min" : [
[
-1.7976931348623157e+308,
1135194602
]
],
"max" : [
[
1135194602,
1.7976931348623157e+308
]
]
},
"server" : "ccc:27017"
}
如果
块
记录的范围从不重叠,则可以通过以下方法更快地完成此任务:
db.block.find({min:{$lte:value}}).sort({min:-1}).limit(1)
这个查询几乎会立即返回,因为它可以通过在索引中进行简单的查找找到记录
您正在运行的查询速度很慢,因为这两个子句在数百万条必须合并的记录上都匹配。事实上,我认为如果在
min
和max
上使用单独的索引,您的查询将运行得更快(可能更快),因为复合索引的max
部分只能用于给定的min
——而不是搜索具有特定max的文档,这是一段很长的时间——您有多少RAM?这是什么版本的MongoDB?您能在查询运行时运行mongostat并捕获其输出吗?@AsyaKamsky正如Leopd正确指出的,这并不是真的出人意料,数据库必须搜索大量记录(查看解释输出)。除非MongoDB支持几何索引,否则这只是生活中的事实,或者我必须使用一些技巧(现在评估他):)它确实支持2d索引,但它们的语义是专门针对geo的。不过,如果你能想出一些聪明的应用程序,它可能会对你有用。2d索引可以非常有效地用于重叠范围查询-它不必是实际坐标,只需开始、结束对(例如,在这种情况下,我需要1d索引:)使用线段(我可以重新利用2d,将第二坐标锁定为0)。然后我会调用geoNear()来查找距离我的点“最近”(距离为0)的线段@AsyaKamsky让我知道如果你想让我试试看,那正是我想要的。我唯一需要添加的是检查max
的值,如果找到了元素(因为范围中有孔)。非常感谢。除了您对查询速度慢的原因不正确之外,没有两个返回数百万的子句将被合并。问题是索引的前导部分与一个不等式一起使用,该不等式没有提供太多的选择性。@Asya同意最大的问题是max
上没有可用的索引,因此它必须扫描集合。但我认为,要使该策略真正有效,mongo必须支持索引交叉点,但它还没有: