12

逆範囲検索のような次のクエリがあります。

db.ip_ranges.find({ $and: [{ start_ip_num: { $lte: 1204135028 } }, { end_ip_num: { $gt: 1204135028 } }] })

$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
            ]
        ]
    }
}

編集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
            ]
        ]
    }
}

ただし、パフォーマンスはまだ不十分です (秒単位)。

4

4 に答える 4

8

そのため、Mongo では二重範囲クエリはお勧めできません。両方を含む単一のインデックスがあると仮定します{start_ip_num: 1, end_ip_num: 1}

それでも十分に近づけない場合 (多くの場合、最初のフィールドによって返されるデータが十分にある場合でも、多くの場合、多くの B ツリー スキャンを実行する必要があるため、それでも遅くなります)、これに対抗するために実行できるトリックが 1 つあります。 2D ボックス クエリを使用します (一度に 2 つの範囲に対してのみ機能します)。

基本的に、[start_ip, end_ip] のように、配列内の 2 つのポイントを含むフィールドに 2D ジオ インデックスを配置し、十分に高い最小/最大値を指定して、デフォルトでちょうど-180/180。

最後に、最小値からボックスの 1 つの隅の $lte 値までの範囲と、ボックスのもう 1 つの隅の gt 値と最大値までの範囲で境界クエリを使用します。構文については、 http://www.mongodb.org/display/DOCS/Geospatial+Indexing#GeospatialIndexing-BoundsQueriesを参照してください。

次のようになります。

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

ここで、max は使用できる最大の IP です。

これを見てからしばらく時間が経っているので、ボックスが間違っている可能性がありますが、コンセプトは適切であり、通常の 2 フィールド B ツリー インデックスよりもダブル レンジ クエリのパフォーマンスが少し向上しました。通常のインデックスの数秒と比較して、一貫して 1 秒未満 (通常は数百ミリ秒) です。塩の。結果は、データと範囲のサイズによって大きく異なります。

更新:bits設定を試して、低い数値と高い数値を試して、違いが生じるかどうかを確認することをお勧めします。私にとっては、平均してクエリに影響を与えるようには見えませんでした。構文については、 http://www.mongodb.org/display/DOCS/Geospatial+Indexing#GeospatialIndexing-CreatingtheIndexを参照してください。

于 2012-10-24T20:56:42.943 に答える
7

Ip2location Web サイトによると、範囲クエリを使用せずに mongodb を使用して IP アドレスの高速クエリを実行できます。mongodb { ip_to: 1 }にインデックスを 1 つだけ作成し、次のように IP をクエリします。

db.collection_name.find({ ip_to: { $gte : ip_integer } }).sort({ ip_end: 1 }).limit(1)

この構成では、600 万のドキュメント コレクションで 1 ミリ秒のクエリ時間を取得しました。

于 2016-01-07T18:11:48.267 に答える
0

たくさんの実験と研究の後、私はこれに出くわしました:

https://groups.google.com/forum/?fromgroups=#!topic/mongodb-user/IUwOzWsc0Sg

このクエリを使用して、約 200 ~ 300 ミリ秒でクエリを取得でき、すべてのインデックスを削除できます(これを機能させるには、すべてのインデックスを削除する必要があります!!! )。

db.ip_ranges.find({start_ip_num: {$lte: 1204135028}, end_ip_num: {$gt: 1204135028}}).limit(1)

理由を聞かないでください。説明できません。興味があれば、私は MongoDB を使用して MaxMind から GeoIP データベースを構築していました。

于 2012-10-25T06:07:16.687 に答える