【问题标题】:Searching for ranges in mongo在mongo中搜索范围
【发布时间】:2013-04-13 11:41:14
【问题描述】:

当输入数据是单个值并且集合数据包含最小/最大范围时,在 Mongo 中查找数据的最有效方法是什么?例如:

record = { min: number, max: number, payload }

需要为记录的最小/最大范围内的数字查找记录。范围从不相交。范围的大小无法预测。

该集合中有大约 600 万条记录。如果我解压缩范围(范围内的每个值都有记录),我会查看大约 4B 条记录。

我已经创建了{min:1,max:1} 的复合索引,但尝试使用:

db.block.find({min:{$lte:value},max:{$gte:value})

... 从几秒到几十秒不等。下面是explain()getIndexes() 的输出。有什么技巧可以让搜索执行得更快吗?

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"
}

【问题讨论】:

  • 那是很长一段时间 - 你有多少内存?这是什么版本的MongoDB?你能在查询运行时运行 mongostat 并捕获它的输出吗?
  • @AsyaKamsky 正如 Leopd 所说的那样,这并不意外,数据库必须搜索大量记录(查看解释输出)。除非 MongoDB 支持几何索引,否则这只是生活中的事实,否则我必须使用一些技巧(现在评估他的):)
  • 它确实支持二维索引,但它们的语义是专门针对地理的。如果您想出一些聪明的应用程序,它仍然可能对您有用。
  • 二维索引可以非常有效地用于重叠范围查询 - 它不必是实际坐标,只需开始、结束对(例如)
  • 在这种情况下我需要一个 1d 索引 :) 使用 LineSegment(我可以为此重新调整 2d 的用途,将第二个坐标锁定为 0)。然后我会调用 geoNear() 来找到离我的点最近的(距离 0)段。 @AsyaKamsky 让我知道你是否想让我尝试一下。

标签: mongodb optimization database


【解决方案1】:

如果您的 block 记录的范围从不重叠,那么您可以通过以下方式更快地完成此操作:

db.block.find({min:{$lte:value}}).sort({min:-1}).limit(1)

这个查询几乎会立即返回,因为它可以通过简单的索引查找找到记录。

您正在运行的查询很慢,因为这两个子句每个都匹配数百万条必须合并的记录。事实上,我认为您的查询会在 minmax 上使用单独的索引运行得更快(可能更快),因为复合索引的 max 部分只能用于给定的 min - 不能搜索具有特定max 的文档。

【讨论】:

  • 这正是我想要的。我唯一需要添加的就是检查max 的值是否找到了一个元素(因为范围中有漏洞)。谢谢!
  • 除了您对查询速度慢的原因不正确 - 没有两个返回数百万的子句将被合并。问题是索引的前导部分与不提供太多选择性的不等式一起使用。
  • @Asya 同意最大的问题是max 上没有可用的索引,因此它必须扫描集合。但我认为要使该策略真正有效,mongo 必须支持它尚未支持的索引交集:jira.mongodb.org/browse/SERVER-3071
猜你喜欢
  • 2016-11-07
  • 2019-08-12
  • 2013-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-01
  • 2016-09-10
  • 2014-11-01
相关资源
最近更新 更多