デフォルトでは、クエリは一致するドキュメントのすべてのフィールドを返します。すべてのフィールドが必要な場合、完全なドキュメントを返す方が、サーバーに投影基準を使用して結果セットを操作させるよりも効率的です。
ただし、プロジェクションを使用してクエリ結果から返されるフィールドを制限すると、次のようにしてパフォーマンスを向上させることができます。
- クエリ結果から不要なフィールドを削除する(ネットワーク帯域幅を節約する)
- 結果フィールドを制限して対象クエリを実現する(完全なドキュメントをフェッチせずにインデックス付きクエリ結果を返す)
プロジェクションを使用して未使用のフィールドを削除する場合、MongoDBサーバーは各ドキュメント全体をメモリにフェッチし(まだそこにない場合)、結果をフィルターして返す必要があります。このプロジェクションを使用しても、MongoDBサーバーのメモリ使用量やワーキングセットは削減されませんが、データモデルと予測されるフィールドに応じて、クエリ結果のネットワーク帯域幅を大幅に節約できます。
対象クエリは、クエリ結果のすべての要求されたフィールドが使用されるインデックスに含まれる特殊なケースであるため、サーバーはドキュメント全体をフェッチする必要はありません。カバーされたクエリは、(ドキュメントのフェッチを回避することにより)パフォーマンスとメモリ使用量(他のクエリが同じドキュメントのフェッチを必要としない場合)を改善できます。
例
mongo
シェルを介したデモ目的で、次のようなドキュメントがあるとします。
db.data.insert({
a: 'webscale',
b: new Array(10*1024*1024).join('z')
})
フィールドb
は、値の選択(またはこの場合は非常に長い文字列)を表す場合があります。
次に、{a:1}
ユースケースによってクエリされる一般的に使用されるフィールドであるインデックスを作成します。
db.data.createIndex({a:1})
findOne()
射影基準のない単純なものは、約10MBのクエリ結果を返します。
> bsonsize(db.data.findOne({}))
10485805
プロジェクション{a:1}
を追加すると、出力がフィールドa
とドキュメント_id
(デフォルトで含まれています)に制限されます。MongoDBサーバーは引き続き2つのフィールドを選択するために10 MBのドキュメントを操作していますが、クエリ結果は33バイトのみになっています。
> bsonsize(db.data.findOne({}, {a:1}))
33
_id
値を見つけるにはドキュメント全体をフェッチする必要があるため、このクエリは対象外です。_id
フィールドは、それが文書の一意の識別子であるため、デフォルトでは、クエリ結果に含まれていますが、_id
明示的に追加しない限り、二次インデックスに含まれません。
結果のtotalDocsExamined
とtotalKeysExamined
メトリックは、explain()
調査されたドキュメントとインデックスキーの数を示します。
> db.data.find(
{a:'webscale'},
{a:1}
).explain('executionStats').executionStats.totalDocsExamined
> 1
このクエリは、射影を使用して_id
フィールドを除外し、{a:1}
インデックスのみを使用して対象クエリを実行することで改善できます。カバーされたクエリは、最大10MBのドキュメントをメモリにフェッチする必要がなくなったため、ネットワークとメモリの両方の使用において効率的になります。
> db.data.find(
{a:'webscale'},
{a:1, _id:0}
).explain('executionStats').executionStats.totalDocsExamined
0
> bsonsize(db.data.findOne( {a:'webscale'},{a:1, _id:0}))
21
MongoDBクエリが遅い。サブセットを返すと、遅いクエリに影響がありますか(フィールドに複合インデックスがあります)?
これは、特定のクエリ、サンプルドキュメント、および完全な説明出力のコンテキストなしでは答えられません。ただし、プロジェクションがある場合とない場合の同じクエリに対して、独自の環境でベンチマークを実行して結果を比較することもできます。予測によってクエリの実行時間全体(処理と結果の転送)に大幅なオーバーヘッドが追加される場合、これはデータモデルが改善される可能性があることを強く示唆しています。
クエリが遅い理由が明確でない場合は、調査する特定の詳細を含む新しい質問を投稿するのが最善です。