MongoDBの3:クエリーの最適化
4271 ワード
前提:テストデータベースには100万件のデータがあり、それぞれ{"user":"user:0-100000","age:"0-100","createAt":new Date()}フィールドが格納されている。
たとえば、「user:1080」未満のuserフィールドと40歳の年齢の人をクエリーします.
√
db.foo.find({"user":{"$lt":"user: 1080"},"age":40}).hint({"age":1,"user":1})
× db.foo.find({"user":{"$lt":"user: 1080"},"age":40}).hint({"user":1,"age":1})
db.foo.find({"user":{"$lt":"user: 1080"},"age":40}).hint({"user":1,"age":1})
たとえば、「user」フィールドの昇順、「age」フィールドの昇順:(単一フィールドインデックス)
√
db.foo.find().sort({"user":1,"age":1}).hint({"user":1})
× db.foo.find().sort({"user":1,"age":1}).hint({"age":1})
(マルチフィールドインデックス)
√
db.foo.find({"age":21}).sort({"user":-1}).hint({"age":1,"user":1})
× db.foo.find({"age":21}).sort({"user":-1}).hint({"user":1,"age":1})
db.foo.find().sort({"user":1,"age":1}).hint({"age":1})
db.foo.find({"age":21}).sort({"user":-1}).hint({"age":1,"user":1})
db.foo.find({"age":21}).sort({"user":-1}).hint({"user":1,"age":1})
たとえば、21歳のユーザーを検索し、ユーザーの順序に従って並べ替えます.
√
db.foo.find({"age":21}).sort({"user":-1}).hint({"age":1,"user":1})
このインデックスには既に秩序があり,逆シーケンスでもMongoDBはageフィールドに基づいて複合条件のエントリを検索して逆ループ出力する.PS:db.collection.EnsureIndex({"age":1,"user":1})MongoDBインデックスは、ageに基づいて昇順され、ageの同じエントリがuserによって昇順ソートされます.(-1は逆順序で並べ替えられます).
√
db.foo.find({"age":{"$gt":15,"$lt":30}}).sort({"user":-1}).hint({"age":1,"user":1})// 。
× db.foo.find({"age":{"$gt":15,"$ lt":30}}).sort({"user":-1}).hint({"user":1,"age":1})// 。
メモリでソートしないと、ソートをメモリに置くよりも遅くなります.メモリに大量のデータを並べ替えるとパフォーマンスが犠牲になるのは間違いないが、データが多すぎる(32 MBを超える)とMongoDBがエラーになるので、メモリの中で並べ替えないことをお勧めします.また、クエリー範囲を制限すると、MongoDBは数回のマッチング後にインデックスをマッチングしなくなります.この場合、ソートキーを前に置くのは非常に良いポリシーです.
db.foo.find({"age":{"$gt":15,"$ lt":30}}).sort({"user":-1}).hint({"user":1,"age":1})// 。
√
db.foo.find({"age":{"$gt":15,"$lt":30}}).sort({"user":-1}).limit(1000).hint({"user":1,"age":1})// 。
//executionTimeMillis: 16
//totalKeysExamined: 8693
× db.foo.find({"age":{"$gt":15,"$lt":30}}).sort({"user":-1}).limit(1000).hint({"age":1,"user":1})// 。
//executionTimeMillis: 495
//totalKeysExamined: 231689
出力エントリを制限すると、クエリ効率は、メモリ内でソートされないインデックスクエリ時間が16 msで、一致するドキュメントが8693件であることを推奨します.メモリでソートする時間は495 msで、一致するドキュメントは231689件です.このように、返されるエントリ数を制限すると、メモリでソートしないほうがずっと速くなります.実際のアプリケーションでは、範囲クエリーが必要なデータをソートすると、一般的に前の結果が得られるので、{「sortKey」:1,「queryCriteria」:1}というインデックスを使用することをお勧めします.このインデックスは、ソートキーをインデックスの前に、クエリー条件をインデックスの後ろに、このインデックスのソートはメモリでは行われず、クエリーエントリを制限する場合に非常に優れています.もちろん、すべてのデータを取得する必要がある場合は、{"queryCriteria":1,"sortKey":1}を使用します.この方法は比較的速いのでなくしますが、メモリの中でソートされ、32 MBの制限に注意してください.一般的には、{"sortKey":1,"queryCriteria":1}インデックスを使用することをお勧めします.
まとめ
db.foo.find({"age":{"$gt":15,"$lt":30}}).sort({"user":-1}).limit(1000).hint({"age":1,"user":1})// 。
//executionTimeMillis: 495
//totalKeysExamined: 231689
// ( ), --> {"sortKey":1,"queryCerteria":1}
db.foo.find({"age":{"$gt":15,"$lt":30}}).sort({"user":-1}).limit(1000).hint({"user":1,"age":1})
// , --> {"queryCerteria":1,"sortKey":1}
db.foo.find({"age":21}).sort("user":-1).hint({age:1,user:1})