0

次のスキーマを持つ CIDR 範囲のコレクションがあります。

{ bottom: Number
top: Number
cidrText: String
live: Boolean
hits: Number }

私がやろうとしているのは、IP が下位 + 上位の範囲内にあるかどうかを確認することです (そして、そのレコードのヒットに対して $inc 更新を実行します。

現時点で私のインデックスは次のとおりです。

db.tbl.ensureIndex( { bottom: 1, top: 1, live: 1 } );

しかし、クエリを実行すると、クエリの一部のみがインデックスを使用し、サーバーのパフォーマンスに大きな影響を与えます。

私のクエリは次のとおりです。

db.tbl.find({ live: true, top: { $gte: 3266341261 }, bottom: { $lte: 3266341261 } })

説明出力は次のとおりです。

{
    "cursor" : "BtreeCursor top_1",
    "isMultiKey" : false,
    "n" : 0,
    "nscannedObjects" : 0,
    "nscanned" : 0,
    "nscannedObjectsAllPlans" : 0,
    "nscannedAllPlans" : 7,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 0,
    "indexBounds" : {
        "top" : [
            [
                3266341261,
                1.7976931348623157e+308
            ]
        ]
    },
    "server" : "local:27017"
}

$gte と $lte の両方で同じインデックスを使用する方法はありますか? または、2 つのクエリを実行して、両方のクエリで一致する行を見つける必要がありますか?

編集 既存のインデックスをすべて削除し、複合インデックスを再度追加したところ、正しい境界が得られましたが、nscanned はまだ高くなっています。

{
    "cursor" : "BtreeCursor bottom_1_top_1_live_1",
    "isMultiKey" : false,
    "n" : 0,
    "nscannedObjects" : 0,
    "nscanned" : 4748,
    "nscannedObjectsAllPlans" : 4746,
    "nscannedAllPlans" : 9494,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 15,
    "indexBounds" : {
        "bottom" : [
            [
                -1.7976931348623157e+308,
                3633904421
            ]
        ],
        "top" : [
            [
                3633904421,
                1.7976931348623157e+308
            ]
        ],
        "live" : [
            [
                true,
                true
            ]
        ]
    },
    "server" : "local27017"
}

また、ログにこれを取得します:

warning: ClientCursor::yield can't unlock b/c of recursive lock ns: col.tbl top: { opid: 25701683, active: true, secs_running: 0, op: "query", ns: "tbl", query: { findandmodify: "tbl", query: { live: true, top: { $gte: 1584813140 }, bottom: { $lte: 1584813140 } }, sort: {}, new: 1, remove: 0, upsert: 0, update: { $inc: { hits: 1 } } }, client: "127.0.0.1:39407", desc: "conn581", threadId: "0x497ec940", connectionId: 581, locks: { ^: "w", ^tbl: "W" }, waitingForLock: false, numYields: 0, lockStats: { timeLockedMicros: {}, timeAcquiringMicros: { r: 0, w: 3 } } }

編集 2

「検索パラメーターの順序」を明確にしすぎると、検索語の順序がインデックスの順序と一致する必要があるように見えます(少なくとも 2.4.4 では)。これら 2 つのクエリを実行すると、1 つは完全なインデックスを使用し、もう 1 つは使用しません。

> db.tbl.find({top: {$lte: 1454442030}, bottom: {$gte: 1454442030}}).explain()
{
    "cursor" : "BtreeCursor top_1",
    "isMultiKey" : false,
    "n" : 2,
    "nscannedObjects" : 2271,
    "nscanned" : 2271,
    "nscannedObjectsAllPlans" : 6816,
    "nscannedAllPlans" : 11396,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 24,
    "indexBounds" : {
        "top" : [
            [
                -1.7976931348623157e+308,
                1454442030
            ]
        ]
    },
    "server" : "local:27017"
}

> db.tbl.find({bottom: {$lte: 1454442030}, top: {$gte: 1454442030}}).explain()
{
    "cursor" : "BtreeCursor bottom_1_top_1_live_1",
    "isMultiKey" : false,
    "n" : 2,
    "nscannedObjects" : 2,
    "nscanned" : 2080,
    "nscannedObjectsAllPlans" : 6240,
    "nscannedAllPlans" : 10400,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 23,
    "indexBounds" : {
        "bottom" : [
            [
                -1.7976931348623157e+308,
                1454442030
            ]
        ],
        "top" : [
            [
                1454442030,
                1.7976931348623157e+308
            ]
        ],
        "live" : [
            [
                {
                    "$minElement" : 1
                },
                {
                    "$maxElement" : 1
                }
            ]
        ]
    },
    "server" : "local:27017"
}

ありがとう

マーク

4

2 に答える 2

0

この警告は、この find() クエリとは関係ありません。

また、nscanned を高くすべきではないと思いませんか?

基本的に { bottom: { $lte: 3266341261 } } は、これに一致するすべてのインデックス レコードをチェックする必要があり、次に { top: { $gte: 3266341261 } } フィルターを適用する必要があります。Explaing() のインデックス境界を確認してください。これは、期待どおりに正しく適用されていると思います。

以下を実行できますか。{ "nscanned" : 4748 } に近いはずです

db.tbl.find({ bottom: { $lte: 3266341261 } }).explain()
于 2013-06-12T12:56:17.440 に答える