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)
然而,性能仍然很差(几秒钟).
因此,在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万个文档集.
| 归档时间: |
|
| 查看次数: |
6122 次 |
| 最近记录: |