如何使用$ gt和$ lte优化MongoDB查询?

Bry*_*yan 11 mongodb mongodb-query

我有以下查询,有点像反向范围查找:

db.ip_ranges.find({ $and: [{ start_ip_num: { $lte: 1204135028 } }, { end_ip_num: { $gt: 1204135028 } }] })
Run Code Online (Sandbox Code Playgroud)

当仅使用$ lte标识符运行时,查询立即返回.但是当我在同一个查询中使用$ gt和$ lte运行时,它非常慢(以秒为单位).

start_ip_num和end_ip_num字段都被索引.

我该如何优化此查询?

编辑

当我在查询中使用explain()函数时,我得到以下内容:

{
    "cursor" : "BtreeCursor start_ip_num_1",
    "nscanned" : 452336,
    "nscannedObjects" : 452336,
    "n" : 1,
    "millis" : 2218,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "isMultiKey" : false,
    "indexOnly" : false,
    "indexBounds" : {
        "start_ip_num" : [
            [
                -1.7976931348623157e+308,
                1204135028
            ]
        ]
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑2

一旦我添加了复合索引,explain()函数就会返回以下内容:

{
    "cursor" : "BtreeCursor start_ip_num_1_end_ip_num_1",
    "nscanned" : 431776,
    "nscannedObjects" : 1,
    "n" : 1,
    "millis" : 3433,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "isMultiKey" : false,
    "indexOnly" : false,
    "indexBounds" : {
        "start_ip_num" : [
            [
                -1.7976931348623157e+308,
                1204135028
            ]
        ],
        "end_ip_num" : [
            [
                1204135028,
                1.7976931348623157e+308
            ]
        ]
    }
}
Run Code Online (Sandbox Code Playgroud)

然而,性能仍然很差(几秒钟).

Eve*_*man 7

因此,在Mongo中不建议使用双范围查询。我假设您有一个包含两个索引{start_ip_num: 1, end_ip_num: 1}

如果那不能使您足够接近(如果第一个字段返回足够的数据,由于它必须进行大量的B树扫描,那么通常它仍然很慢),您可以采取一种技巧来解决此问题使用2D框查询(一次仅适用于两个范围)。

基本上,您将一个二维地理索引放在包含数组中两个点的字段上,例如[start_ip,end_ip],并为其赋予足够高的最小/最大值,这样它就不会达到默认的限制-180/180。

最后,使用范围查询,范围在框的一个角上从min到$ lte值,在框的另一个角上是gt和max值。有关语法,请参见http://www.mongodb.org/display/DOCS/Geospatial+Indexing#GeospatialIndexing-BoundsQueries

看起来像这样:

db.ip_ranges.find({ip_range:{$within:{$box:[[0, 1204135028], [1204135028, max]]}}});
Run Code Online (Sandbox Code Playgroud)

其中max是您可以拥有的最大IP。

自从我看过这个以来已经有一段时间了,所以框可能是错误的,但是这个概念很合理,这使得双范围查询的性能比常规两字段B树索引更好。持续不到一秒钟(虽然通常是几百毫秒),而使用常规索引的时间却只有几秒钟-我认为我当时有数亿文档,但是已经有一段时间了,因此请认真地使用这些记住的基准盐。我敢肯定,结果会因您的数据和范围大小而有很大差异。

更新:您可能想尝试一下该bits设置,尝试使用较小的数字和较大的数字以查看是否有所不同。对我来说,它似乎并没有平均影响查询。有关语法,请参见http://www.mongodb.org/display/DOCS/Geospatial+Indexing#GeospatialIndexing-CreatingtheIndex


小智 7

根据Ip2location网站,可以使用mongodb在没有范围查询的情况下实现对ip地址的快速查询.在mongodb上只创建一个索引 { ip_to: 1 },并使用以下命令查询ip:

db.collection_name.find({ ip_to: { $gte : ip_integer } }).sort({ ip_end: 1 }).limit(1)
Run Code Online (Sandbox Code Playgroud)

使用此配置,我获得了1毫秒的查询时间和600万个文档集.