2

この問題を理解するのに問題があります-シャードの1つ(シャード2)が間違ったインデックスを使用しているように見えるシャードクラスターがあります。サイトIDと最初のリクエスト時間であるシャードキーでクエリを実行します{ site.id: 1, frt: 1 }。また、サイトIDと最終リクエスト時間のインデックスもあります。

このクエリでは、ドキュメントに設定した2つのブール値によって返されるドキュメントを制限しようとしています。

Mongoのクエリオプティマイザがどのように機能するかについてのドキュメントを読むと、返されたExplainsを見ると、これは特に奇妙に思えます。ここのドキュメント:クエリオプティマイザ

クエリが期待どおりに返されるシャード1からの説明も含めました。最後に、Shard 2にチャンクが保存されていないサイトIDを使用すると、正しいインデックスが使用されますが、スキャンしたり返したりするものはありません。完全を期すために、これについての説明を最後に追加しました。

なぜこれが発生するのか、および/またはこれがバグであるかどうかについてのアイデアはありますか?

基本クエリ(不正なインデックス):

shard2:PRIMARY> db.visit.find({ "site.id": 128, "frt": { $gte: new Date(2012, 8, 24 ) }, "ue": false, "bot": false }).explain()
{
    "cursor" : "BtreeCursor site.id_1_lrt_-1",
    "isMultiKey" : false,
    "n" : 198,
    "nscannedObjects" : 61204,
    "nscanned" : 61204,
    "nscannedObjectsAllPlans" : 61537,
    "nscannedAllPlans" : 61537,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 122,
    "nChunkSkips" : 0,
    "millis" : 727,
    "indexBounds" : {
        "site.id" : [
            [
                128,
                128
            ]
        ],
        "lrt" : [
            [
                {
                    "$maxElement" : 1
                },
                {
                    "$minElement" : 1
                }
            ]
        ]
    },
    "server" : "ip-10-4-211-107:2200"
}

ヒントの提供:

shard2:PRIMARY> db.visit.find({ "site.id": 128, "frt": { $gte: new Date(2012, 8, 24 ) }, "ue": false, "bot": false }).hint("site.id_1_frt_1").explain()
{
    "cursor" : "BtreeCursor site.id_1_frt_1",
    "isMultiKey" : false,
    "n" : 198,
    "nscannedObjects" : 486,
    "nscanned" : 486,
    "nscannedObjectsAllPlans" : 486,
    "nscannedAllPlans" : 486,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 5,
    "indexBounds" : {
        "site.id" : [
            [
                128,
                128
            ]
        ],
        "frt" : [
            [
                ISODate("2012-09-24T07:00:00Z"),
                ISODate("292278995-01--2147483647T07:12:56.808Z")
            ]
        ]
    },
    "server" : "ip-10-4-211-107:2200"
}

追加のブール制約なしの同じクエリ(正しいインデックスを使用):

shard2:PRIMARY> db.visit.find({ "site.id": 128, "frt": { $gte: new Date(2012, 8, 24 ) } }).explain()
{
    "cursor" : "BtreeCursor site.id_1_frt_1",
    "isMultiKey" : false,
    "n" : 486,
    "nscannedObjects" : 486,
    "nscanned" : 486,
    "nscannedObjectsAllPlans" : 486,
    "nscannedAllPlans" : 486,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 1,
    "indexBounds" : {
        "site.id" : [
            [
                128,
                128
            ]
        ],
        "frt" : [
            [
                ISODate("2012-09-24T07:00:00Z"),
                ISODate("292278995-01--2147483647T07:12:56.808Z")
            ]
        ]
    },
    "server" : "ip-10-4-211-107:2200"
}

シャード1では、元のクエリは期待されるインデックスを使用します。

shard1:PRIMARY> db.visit.find({ "site.id": 253, "frt": { $gte: new Date(2012, 8, 24 ) }, "ue": false, "bot": false }).explain()
{
    "cursor" : "BtreeCursor site.id_1_frt_1",
    "isMultiKey" : false,
    "n" : 15615,
    "nscannedObjects" : 15950,
    "nscanned" : 15950,
    "nscannedObjectsAllPlans" : 16152,
    "nscannedAllPlans" : 16152,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 125,
    "nChunkSkips" : 0,
    "millis" : 237,
    "indexBounds" : {
        "site.id" : [
            [
                253,
                253
            ]
        ],
        "frt" : [
            [
                ISODate("2012-09-24T07:00:00Z"),
                ISODate("292278995-01--2147483647T07:12:56.808Z")
            ]
        ]
    },
    "server" : "ip-10-6-50-253:2100"
}

ここにチャンクがないサイトのシャード2でクエリを実行します(正しいインデックスを使用します):

shard2:PRIMARY> db.visit.find({ "site.id": 253, "frt": { $gte: new Date(2012, 8, 24 ), "ue": false, "bot": false } }).explain()
{
    "cursor" : "BtreeCursor site.id_1_frt_1",
    "isMultiKey" : false,
    "n" : 0,
    "nscannedObjects" : 0,
    "nscanned" : 0,
    "nscannedObjectsAllPlans" : 0,
    "nscannedAllPlans" : 0,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 0,
    "indexBounds" : {
        "site.id" : [
            [
                253,
                253
            ]
        ],
        "frt" : [
            [
                ISODate("2012-09-24T07:00:00Z"),
                ISODate("292278995-01--2147483647T07:12:56.808Z")
            ]
        ]
    },
    "server" : "ip-10-4-211-107:2200"
}
4

1 に答える 1

3

最初に、この動作を説明する可能性のある、リンクするドキュメントからのいくつかのこと:

クエリのテストは、1,000 回の操作の後、およびコレクションの特定の操作 (インデックスの追加など) が発生した後に繰り返されます。

そのため、評価するのに十分な量のクエリがない場合、最初の選択肢に固執します。

2番:

これを解決するために、新しいプランをテストするときに、MongoDB は複数のクエリ プランを並行して実行します。1 つが終了するとすぐに他の実行が終了し、システムはどの計画が適切かを学習します。

別のクエリで使用されているなどの理由で、他のインデックスが既にメモリ内にある場合、または優先インデックスでのクエリの実行を遅くする何かが起こっている場合 (または、非常に近く、速度の点でスワップする場合があります)。 、その後、「悪い」インデックスが再び返されます。

オプティマイザは 2.2 で調整および改善されているため、引き続き問題が発生する場合 (および 2.0 以下を使用している場合) は、一見の価値があるかもしれません。または、テストで既に行ったように、使用するのに最適なインデックスがわかっている場合は、疑いをすべて取り除き、ヒントを使用してそれを指定します。

于 2012-09-24T23:29:09.933 に答える