クエリプラン
MongoDB クエリ プランナーは、どのクエリに対しても、使用可能なインデックスを考慮して最も効率的なクエリプランを選択し、キャッシュします。クエリプランの効率性を評価するために、クエリ プランナーはすべての候補プランを試用期間中に実行します。一般的に、選出されるプランは、試用期間中に実行する作業量が最も少なく、最も多くの結果が得られるクエリプランです。
関連付けられているプラン キャッシュ エントリは、同じクエリシェイプを持つ後続のクエリに使用されます。
以下の図はクエリプランナーのロジックを示しています。
注意
explain
を使用すると、既存のすべてのプラン キャッシュ エントリが無視され、MongoDB クエリ プランナーが新しいプラン キャッシュ エントリを作成できなくなります。
プラン キャッシュ エントリの状態
各プランキャッシュのクエリシェイプは、キャッシュ内の3つの状態のうちの1つに関連付けられています。
状態 | 説明 |
---|---|
The entry in the cache is a placeholder entry for this shape. つまり、プランナーは シェイプを確認し、プランに必要な作業量を定量化する値を計算し、 シェイプ プレースホルダー エントリを保存しましたが、クエリシェイプはクエリプランの生成に使用されることはありません。 クエリの場合、シェイプのキャッシュ エントリ状態が非アクティブな場合、次のようになります。
| |
プラン キャッシュの変更をトリガーする追加のシナリオについては、「プラン キャッシュのフラッシュ」を参照してください。
クエリプランとキャッシュ情報
特定のクエリのクエリプラン情報を表示するには、 db.collection.explain()
または cursor.explain()
を使用します。
コレクションのプラン キャッシュ情報を表示するには、$planCacheStats
集計ステージを使用できます。
プラン キャッシュのフラッシュ
mongod
が再起動またはシャットダウンした場合、クエリプランのキャッシュは保持されません。さらに、
インデックスやコレクションの削除などのカタログ操作により、プラン キャッシュが消去されます。
最近の使用頻度が最も少ない(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()
メソッドと同様に、オプティマイザーに期待される動作をオーバーライドするため、インデックス フィルターの使用は控えめにしてください。
MongoDB 6.0 以降、インデックス フィルターは、以前はplanCacheSetFilter
コマンドを使用して設定されていた照合を使用します。