6

私はそのようなタイプのクエリをたくさん実行しています:

db.mycollection.find({a:{$gt:10,$lt:100}, b:4}).sort({c:-1, a:-1})

高速化するには、どのようなインデックスを使用すればよいですか? {a:1, b:1}と の両方が必要だと思いますよ{c:-1, a:-1}ね?または、これらのインデックスは、パフォーマンスの向上なしに何らかの形で互いに干渉しますか?

編集:私にとって実際の問題は、多くのクエリをループで実行することです。それらのいくつかは狭い範囲で実行され、他のクエリは広い範囲で実行されます。index を に{a:1, b:1}設定すると、小さなチャンクが非常に迅速に選択されますが、大きな範囲になると、「インデックスのない sort() にはデータが多すぎます」というエラーが表示されます。それ以外の場合、 index を に配置する{c:-1, a:-1}と、エラーは発生しませんが、小さなチャンク (およびそれらのチャンクが多い) の処理ははるかに遅くなります。では、狭い範囲の選択の速さを維持しながら、大量のデータでエラーが発生しないようにするにはどうすればよいでしょうか?

問題があれば、Python の pymongo を介してクエリを実行します。

4

5 に答える 5

4

免責事項: MongoDB v2.4 の場合

ヒントを使用すると、選択したインデックスをクエリに強制的に使用させることができるため、満足するまでさまざまなインデックスを使用してクエリを最適化できます。欠点は、リクエストごとに独自のインデックスを設定していることです。コレクション全体にインデックスを設定し、特に繰り返し使用されるクエリ の場合は、Mongo に正しい (最速の) インデックスを選択させることを好みます。

クエリには 2 つの問題があります。

  • インデックスが作成されていないパラメーターでソートしないでください。次のエラーが表示されます: 「インデックスのない sort() にはデータが多すぎます」。ドキュメントの量.find()が非常に大きい場合、サイズは使用する mongo のバージョンによって異なります。これは、クエリが機能するためには、インデックスが必要であることを意味します。AC
  • 次に、より大きな問題について説明します。Mongo では機能しない範囲クエリ ($ltおよび$gton param ) を実行しています。AMongoDB は一度に 1 つのインデックスのみを使用します。同じパラメーターで 2 つのインデックスを使用しています。コードでこれを処理するための解決策がいくつかあります。

    1. r = range( 11,100 )
      db.mycollection.find({a:{$in: r }, b:4}).sort({c:-1, a:-1})

    2. クエリでのみ$ltまたはを使用し て、結果を取得し、Python コードでフィルター処理します。 このソリューションはより多くのデータを返すため、結果が何百万件もある場合は使用しないでください。 このオプションを選択する場合は、 と で複合キーを使用していることを確認しください。 $gt
      db.mycollection.find({ a: { $lt:100 }, b:4}).sort({c:-1, a:-1})
      A=11
      AB

$or$or は、インデックスの使用よりも効率的に最適化されていないため、クエリで使用する場合は注意してください。$in

于 2013-10-07T14:04:15.270 に答える
2

インデックス {c:-1,a:-1,b:1} を定義すると、いくつかの考慮事項に役立ちます。

このオプションを使用すると、インデックスは完全にスキャンされますが、インデックス値に基づいて適切なドキュメントのみが参照され、正しい順序で参照されるため、結果を取得した後に順序付けフェーズは必要ありません。インデックスが巨大な場合、どのように動作するかわかりませんが、結果が小さい場合は遅くなると思いますが、結果セットが大きい場合は速くなります。

プレフィックス マッチングについて。インデックスと下位レベルが、それらのレベルが使用されるクエリを提供するために使用できることを示唆している場合。この動作を実証するために、短いテストを行いました。

以下を使用してテストデータを準備しました。

> db.createCollection('testIndex')
{ "ok" : 1 }
> db.testIndex.ensureIndex({a:1,b:1})
> db.testIndex.ensureIndex({c:-1,a:-1})
> db.testIndex.ensureIndex({c:-1,a:-1,b:1})
> for(var i=1;i++<500;){db.testIndex.insert({a:i,b:4,c:i+5});}
> for(var i=1;i++<500;){db.testIndex.insert({a:i,b:6,c:i+5});}

ヒント付きのクエリの結果:

> db.testIndex.find({a:{$gt:10,$lt:100}, b:4}).hint('c_-1_a_-1_b_1').sort({c:-1, a:-1}).explain()
{
    "cursor" : "BtreeCursor c_-1_a_-1_b_1",
    "isMultiKey" : false,
    "n" : 89,
    "nscannedObjects" : 89,
    "nscanned" : 588,
    "nscannedObjectsAllPlans" : 89,
    "nscannedAllPlans" : 588,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 1,
    "indexBounds" : {
        "c" : [
            [
                {
                    "$maxElement" : 1
                },
                {
                    "$minElement" : 1
                }
            ]
        ],
        "a" : [
            [
                100,
                10
            ]
        ],
        "b" : [
            [
                4,
                4
            ]
        ]
    },
    "server" :""
}

出力の説明は、インデックスがスキャンされることです。これが、 nscannedが 588 (スキャンされたインデックス エントリとドキュメントの数) である理由です。nscannedObjectsの数は、スキャンされたドキュメントの数です。したがって、インデックスに基づいて、mongo は基準に一致するドキュメントのみを読み取ります (インデックスは部分的にカバーするか、またはその程度です)。ご覧のとおり、scanAndOrder は false であるため、並べ替えフェーズはありません。(これは、インデックスが高速になるメモリ内にあるかどうかを意味します)

他の人がリンクした記事とともに:http://blog.mongolab.com/wp-content/uploads/2012/06/IndexVisitation-4.png最初にソートキーをインデックスに配置し、クエリキーを後に配置する必要があります。サブセットが一致する場合は、並べ替え基準とまったく同じ順序でサブセットを含める必要があります (クエリ部分には関係ありません)。

于 2013-10-01T15:50:36.167 に答える
0

検索でフィールドの順序を変更した方が良いと思います。

db.mycollection.find({b:4, a:{$gt:10,$lt:100}}).sort({c:-1, a:-1})

次に、インデックスを追加します

{b:1,a:-1,c:-1}
于 2013-10-03T09:33:00.767 に答える
0

2つの異なるインデックスを試しましたが、

の順序でインデックスを持つものdb.mycollection.ensureIndex({a:1,b:1,c:-1})

そして説明計画は以下のようでした

{
    "cursor" : "BtreeCursor a_1_b_1_c_-1",
    "nscanned" : 9542,
    "nscannedObjects" : 1,
    "n" : 1,
    "scanAndOrder" : true,
    "millis" : 36,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "isMultiKey" : false,
    "indexOnly" : false,
    "indexBounds" : {
        "a" : [
            [
                3,
                10000
            ]
        ],
        "b" : [
            [
                4,
                4
            ]
        ],
        "c" : [
            [
                {
                    "$maxElement" : 1
                },
                {
                    "$minElement" : 1
                }
            ]
        ]
    }
}

およびその他のインデックスdb.mycollection.ensureIndex({b:1,c:-1,a:-1})

> db.mycollection.find({a:{$gt:3,$lt:10000},b:4}).sort({c:-1, a:-1}).explain()
{
    "cursor" : "BtreeCursor b_1_c_-1_a_-1",
    "nscanned" : 1,
    "nscannedObjects" : 1,
    "n" : 1,
    "millis" : 8,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "isMultiKey" : false,
    "indexOnly" : false,
    "indexBounds" : {
        "b" : [
            [
                4,
                4
            ]
        ],
        "c" : [
            [
                {
                    "$maxElement" : 1
                },
                {
                    "$minElement" : 1
                }
            ]
        ],
        "a" : [
            [
                10000,
                3
            ]
        ]
    }
}
> 

ある範囲の値に対して「a」をクエリし、特定の値に対して「b」をクエリしているので、2番目のオプションの方が適切だと思います。nscanned オブジェクトが 9542 から 1 に変更されました

于 2013-10-03T16:03:04.123 に答える