クエリの最適化は、クエリ操作で加工する必要があるデータ量を減らすことで、読み取り操作の効率を向上させます。インデックス、プロジェクション、クエリ制限を使用して、クエリのパフォーマンスを向上させ、リソース消費を削減します。
クエリをサポートするインデックスの作成
よく実行されるクエリにインデックスを作成します。クエリが複数のフィールドを検索する場合は、複合インデックスを作成します。インデックスを使用するとパフォーマンスが向上します。これは、インデックスがない場合、クエリはコレクション内のすべてのドキュメントをスキャンする必要があるためです。
例、inventory
コレクションの type
フィールドに対する次のクエリを考えてみましょう。
let typeValue = <someUserInput>; db.inventory.find( { type: typeValue } );
このクエリのパフォーマンスを向上させるには、type
フィールドの inventory
コレクションにインデックスを追加します。[1] mongosh
では、db.collection.createIndex()
メソッドを使用してインデックスを作成します。
db.inventory.createIndex( { type: 1 } )
クエリ パフォーマンスを分析するには、クエリ パフォーマンスの分析を参照してください。
[1] | 単一フィールド インデックスの場合、インデックスの順序は重要ではありません。複合インデックスの場合、フィールドの順序はインデックスがサポートするクエリに影響します。詳細については、ソート順序を参照してください。 |
選択性のあるクエリの作成
クエリの選択性とは、クエリ述語がコレクション内のドキュメントをどの程度適切にフィルタリングするかを指します。クエリの選択性によって、クエリがインデックスを効果的に使用できるかどうかが決まります。
選択性の高いクエリほど、一致するドキュメントの割合は少なくなります。たとえば、ユニークな _id
フィールドでの等価一致は、多くとも 1 件のドキュメントにしか一致しないため、選択性が非常に高くなります。
選択性の低いクエリは一致するドキュメントの割合は多くなるため、インデックスを効果的に使用できません。
たとえば、不等式演算子 $nin
と $ne
は、インデックスの大部分と一致することが多いため、あまり選択的ではありません。その結果、多くの場合、インデックス付きの $nin
クエリまたは $ne
クエリのパフォーマンスは、コレクション内のすべてのドキュメントをスキャンする必要がある $nin
クエリまたは $ne
クエリのパフォーマンスと同程度になる可能性があります。
regular expressions
の選択性は式自体に依存します。詳細については、「正規表現とインデックスの使用」をご覧ください。
プロジェクトに必要なデータのみ
ドキュメントの一部のフィールドセットが必要な場合は、必要なフィールドのみを返すことでパフォーマンスを向上できます。プロジェクションにより、ネットワーク トラフィックと処理時間が削減されます。
例、posts
コレクションへのクエリに timestamp
、title
、author
、abstract
フィールドのみが必要な場合は、プロジェクションでそれらのフィールドを指定します。
db.posts.find( {}, { timestamp : 1, title : 1, author : 1, abstract : 1} ).sort( { timestamp : -1 } )
$project
集計ステージを使用する場合、それは通常パイプラインの 最後のステージ であり、クライアントに返すフィールドを指定するために使用されます。
$project
ステージをパイプラインの開始または中間で使用して、後続のパイプラインステージに渡されるフィールドの数を減らしてもパフォーマンスが改善する可能性はほとんどありません。データベースではこの最適化が自動的に実行されているためです。
プロジェクションの使用方法の詳細については、「クエリから返されるプロジェクト フィールド」を参照してください。
クエリ結果を制限する
MongoDB カーソル は結果をバッチで返します。必要な結果の数がわかっている場合は、limit()
メソッドでその値を指定します。結果を制限すると、ネットワーク リソースの需要が減ります。
一般的に、結果を制限すると、結果がソートされ、どのドキュメントが返されるかがわかっている場合に最も便利です。例、posts
コレクションへのクエリから 10 の結果のみが必要な場合は、次のクエリを実行します。
db.posts.find().sort( { timestamp : -1 } ).limit(10)
結果の制限の詳細については、limit()
を参照してください。
インデックス ヒントの使用
クエリオプティマイザは通常、特定の操作に最適なインデックスを選択します。ただし、hint()
メソッドを使用してMongoDBに特定のインデックスを強制的に使用させることもできます。hint()
パフォーマンス テストをサポートする場合、または複数のインデックスに表示されるフィールドをクエリしてMongoDB が正しいインデックスを使用していることを保証する場合は、を使用します。
サーバーサイド操作の使用
MongoDB の $inc
演算子を使用して、ドキュメント内の値を増減します。演算子は、ドキュメントを選択し、クライアントで簡単な変更を加え、その後ドキュメント全体をサーバーに書き込む の代わりに、サーバー側でフィールドの値を増加します。$inc
演算子は、2 つのアプリケーションインスタンスがドキュメントをクエリし、フィールドを手動で増加させて、ドキュメント全体を同時に保存するときに発生する競合状態を回避するのにも役立ちます。
カバード クエリの実行
カバード クエリとは、インデックスを使用して処理が完了し、ドキュメントを調査する必要がないクエリです。次のすべてが当てはまる場合、インデックスはクエリをカバーします。
クエリ内のすべてのフィールド(アプリケーションで指定されたフィールドと、シャーディングなどの内部で必要なフィールドの両方)はインデックスの一部です。
結果に返されるすべてのフィールドは同じインデックスにある
クエリ内のどのフィールドも
null
に等しくありません。たとえば、次のクエリ述語ではカバード クエリは作成されません。{ "field": null }
{ "field": { $eq: null } }
例
inventory
コレクションの type
フィールドと item
フィールドには次のインデックスがあります。
db.inventory.createIndex( { type: 1, item: 1 } )
このインデックスでは、type
フィールドと item
フィールドをクエリし、item
フィールドのみを返す次の操作をカバーします。
db.inventory.find( { type: "food", item:/^c/ }, { item: 1, _id: 0 } )
指定されたインデックスがクエリをカバーするには、インデックスに _id
フィールドが含まれていないため、プロジェクション ドキュメントは _id: 0
を明示的に指定して結果から _id
フィールドを除外する必要があります。
埋め込みドキュメント
インデックスは、埋め込みドキュメント内のフィールドに対するクエリをカバーできます。
たとえば、次の形式のドキュメントを含む userdata
コレクションを考えてます。
db.userdata.insertOne( { _id: 1, user: { login: "tester" } } )
コレクションには、次のインデックスがあります。
db.userdata.createIndex( { "user.login": 1 } )
{ "user.login": 1 }
インデックスは、次のクエリをカバーします。
db.userdata.find( { "user.login": "tester" }, { "user.login": 1, _id: 0 } )
注意
埋め込みドキュメントのフィールドにインデックスを付けるには、ドット表記を使用します。「埋め込みフィールドでのインデックスを作成する」を参照してください。
マルチキーのカバーリング
マルチキー インデックスは、どのフィールドがインデックスをマルチキーにするかを追跡する場合、非配列フィールドに対するクエリをカバーできます。
マルチキー インデックスは、配列フィールドに対する カバー クエリは実行できません。
マルチキー インデックスを使用したカバード クエリの例については、マルチキー インデックスのページのカバード クエリを参照してください。
パフォーマンス
インデックスにはクエリに必要なすべてのフィールドが含まれているため、MongoDB はクエリ条件を一致させることも、インデックスのみを使用して結果を返すこともできます。
インデックスのみをクエリする方が、インデックス外のドキュメントをクエリするよりもはるかに高速です。インデックス キーは通常、カタログするドキュメントよりも小さく、インデックスは通常 RAM で利用可能か、ディスク上に連続してに配置されます。
制限
インデックス タイプ
すべてのインデックス タイプがクエリをカバーできるわけではありません。対象となるインデックスのサポートの詳細については、対応するインデックス タイプのドキュメント ページを参照してください。
シャーディングされたコレクション
mongos
で実行すると、インデックスにシャードキーが含まれている場合にのみ、シャーディングされたコレクションのクエリをカバーできます。
explain の結果
クエリがカバード クエリであるかどうかを判断するには、db.collection.explain()
メソッドまたは explain()
メソッドを使用します。「カバード クエリ」を参照してください。