MongoDB クエリ プランナーは、どのクエリに対しても、使用可能なインデックスを考慮して最も効率的なクエリプランを選択し、キャッシュします。クエリプランの効率性を評価するために、クエリ プランナーはすべての候補プランを試用期間中に実行します。一般的に、選出されるプランは、試用期間中に実行する作業量が最も少なく、最も多くの結果が得られるクエリプランです。
関連付けられているプラン キャッシュ エントリは、同じクエリシェイプを持つ後続のクエリに使用されます。
以下の図はクエリプランナーのロジックを示しています。
プラン キャッシュ エントリの状態
各プラン キャッシュ クエリシェイプは、キャッシュ内の次の 3 つの状態のうちのいずれか 1 つに関連付けられています。
| 状態 | 説明 | 
|---|---|
| このシェイプのエントリはキャッシュに存在しません。 クエリの場合、クエリシェイプのキャッシュエントリ状態が欠落している場合、次のようになります。 
 | |
| The entry in the cache is a placeholder entry for this shape. つまり、プランナーは シェイプを確認し、プランに必要な作業量を定量化する値を計算し、 シェイプ プレースホルダー エントリを保存しましたが、クエリシェイプはクエリプランの生成に使用されることはありません。 クエリの場合、シェイプのキャッシュエントリ状態が 非アクティブ な場合、次のようになります。 
 | |
| キャッシュ内のエントリは勝者プランのものですプランナーはこのエントリを使用してクエリプランを生成できます。 クエリの場合、シェイプのキャッシュエントリ状態が アクティブ の場合、次のようになります。 アクティブなエントリはクエリプランの生成に使用されます。 プランナーはエントリのパフォーマンスも評価し、プランに必要な作業量を定量化する値が選択基準を満たさなくなった場合は、 非アクティブ 状態に移行します。 | 
プラン キャッシュの変更をトリガーする追加のシナリオについては、「プラン キャッシュのフラッシュ」を参照してください。
クエリプランとキャッシュ情報
特定のクエリのクエリプラン情報を表示するには、  db.collection.explain()またはcursor.explain()を使用します。
コレクションのプラン キャッシュ情報を表示するには、$planCacheStats 集計ステージを使用できます。
プラン キャッシュのフラッシュ
mongod が再起動またはシャットダウンした場合、クエリプランのキャッシュは保持されません。さらに、
- すべての DDLイベントにより、関連するコレクションのプランキャッシュがクリアされます。 DDL イベントの例には、コレクションの削除 と、インデックスの作成、削除、または非表示 があります。 
- 最近の使用頻度が最も少ない(LRU)キャッシュを置換するメカニズムにより、状態に関係なく、最近のアクセス頻度が最も少なかったキャッシュ エントリーが消去されます。 
ユーザーは次の操作も可能です。
- PlanCache.clear()メソッドを使用してプラン キャッシュ全体を手動でクリアします。
- PlanCache.clearPlansByQuery()メソッドを使用して、特定のプラン キャッシュのエントリを手動でクリアします。
プラン キャッシュ デバッグ情報のサイズ制限
MongoDB 5.0以降では、すべてのコレクションのplan cachesの累積サイズが0.5より小さい場合にのみ、プラン キャッシュは完全なplan cacheエントリを保存します。 GB。 すべてのコレクションのplan cachesの累積サイズがこのしきい値を超えると、追加のplan cacheエントリが次のデバッグ情報なしで保存されます。
plan cache エントリの推定サイズ(バイト単位)は、$planCacheStats の出力に表示されます。
queryHash および planCacheKey
queryHash
同じクエリ シェイプを持つ低速クエリを識別できるように、各クエリ シェイプは queryHash に関連付けられています。 queryHash は、クエリ シェイプのハッシュを表す 16 進数のstringで、クエリ シェイプのみに依存します。
注意
他のハッシュ関数と同様に、2 つの異なるクエリシェイプで同じハッシュ値が生成される場合があります。ただし、異なるクエリシェイプ間でハッシュ衝突が発生する可能性は低くなります。
planCacheKey
クエリプラン キャッシュに関する詳細なインサイトを提供するために、MongoDB ではplanCacheKeyが提供されています。
planCacheKey  は、クエリに関連付けられたプラン キャッシュ エントリのキーのハッシュです。
注意
queryHash と違って planCacheKey は、クエリシェイプとそのシェイプで現在使用可能なインデックスの両方の関数です。つまり、クエリシェイプのサポートが可能なインデックスが追加または削除された場合、planCacheKey 値は変わる可能性がありますが、queryHash の値は変化しません。
たとえば、次のインデックスを持つコレクション foo を考えます。
db.foo.createIndex( { x: 1 } ) db.foo.createIndex( { x: 1, y: 1 } ) db.foo.createIndex( { x: 1, z: 1 }, { partialFilterExpression: { x: { $gt: 10 } } } ) 
このコレクションに対する次のクエリは、同じシェイプです。
db.foo.explain().find( { x: { $gt: 5 } } )  // Query Operation 1 db.foo.explain().find( { x: { $gt: 20 } } ) // Query Operation 2 
このようなクエリがある場合、部分フィルター式を含むインデックスはクエリ操作 2 をサポートできますが、クエリ操作 1 はサポートしません。クエリ操作 1 をサポートするために使用できるインデックスはクエリ操作 2 とは異なるため、2 つのクエリの planCacheKey は異なります。
いずれかのインデックスが削除された場合、または新しいインデックス { x: 1, a: 1
} が追加された場合、両方のクエリ操作の planCacheKey が変更されます。
可用性
queryHash と planCacheKey は以下で利用可能です。
- explain() 出力フィールド: - queryPlanner.queryHashおよび- queryPlanner.planCacheKey
- 遅いクエリをログに記録するときのプロファイラー ログ メッセージと診断ログ メッセージ(mongod および mongos ログ メッセージ) 。 
- $planCacheStats集計ステージ
- PlanCache.listQueryShapes()メソッドと- planCacheListQueryShapesコマンド
- PlanCache.getPlansByQuery()メソッドと- planCacheListPlansコマンド
インデックス フィルター
インデックス フィルターはplanCacheSetFilterコマンドで設定され、クエリシェイプについてどのインデックスがオプティマイザに評価されるかを決定します。 クエリシェイプは、クエリ、並べ替え、およびプロジェクションの仕様の組み合わせで構成されます。 特定のクエリシェイプに インデックス フィルター が存在する場合、オプティマイザはフィルターで指定されたインデックスのみを考慮します。
クエリシェイプについてのインデックス フィルターが存在する場合、MongoDB は hint() を無視します。MongoDB がクエリシェイプにインデックス フィルターを適用したかどうかを確認するには、db.collection.explain() メソッドまたは cursor.explain() メソッドの indexFilterSet フィールドを確認します。
インデックス フィルターは、オプティマイザが評価するインデックスのみに関係します。オプティマイザは、特定のクエリシェイプの最適なプランとしてコレクションスキャンを選択する場合でも、コレクションスキャンを選択する場合があります。
インデックス フィルターは、サーバープロセスの実行中のみ存在し、シャットダウン後は保持されません。MongoDB には、フィルターを手動で削除するコマンドも用意されています。
インデックス フィルターはhint()メソッドと同様に、オプティマイザーに期待される動作をオーバーライドするため、インデックス フィルターの使用は控えめにしてください。
詳しくは、 planCacheListFilters 、 planCacheClearFilters 、 planCacheSetFilterを参照してください。