この章では、MongoDBのクエリパフォーマンス解析について紹介します。SQLのexplainと同様に、MongoDBもクエリ文のパフォーマンスを解析するためのexplainをサポートしています。

基本的な使用方法

explain関数を呼び出すことで、解析結果を取得できます。

// findメソッドの解析結果
db.collection.find({}).explain();

// aggregateメソッドの解析結果
db.collection.explain().aggregate([]);

explainには3つのモードがあります:

  • queryPlanner (デフォルト)
  • executionStats
  • allPlansExecution

説明:

  • queryPlanner を使用すると、実際のステートメントを実行せず、すべての可能な実行計画をリストアップし、すでに勝利した winningPlan プランを表示します。
  • executionStats を使用すると、winningPlan プランのみを実行し、結果を出力します。
  • allPlansExecution を使用すると、すべてのプランを実行し、結果を出力します。

異なるモードの使用方法

// executionStats モード、explain関数にパラメータを単純に渡す
db.collection.find({}).explain('executionStats');

// allPlansExecution モード
db.collection.find({}).explain('allPlansExecution');

explainコンテンツの説明

queryPlannerコンテンツ

以下の内容は、explainでデフォルトで返されるコンテンツで、非キー情報は無視します。

{
	"queryPlanner" : {
		"plannerVersion" : 1,
		"namespace" : "test.orders",
		"indexFilterSet" : false, // キーメトリクス、インデックスによるデータフィルタリングの使用
		"winningPlan" : {
			"stage" : "COLLSCAN",  // キーメトリクス、ステージフェーズの名前。各フェーズにはフェーズ固有の情報があり、COLLSCANはコレクション全体のスキャンを表します
			"direction" : "forward"
		},
		"rejectedPlans" : [ ]
	}
	...
}

ステージフェーズの種類は以下の通りです:

  • COLLSCAN: フルテーブルスキャン
  • IXSCAN: インデックススキャン
  • FETCH: インデックスを基に特定のドキュメントを取得
  • SHARD_MERGE: 各シャードが返したデータをマージ
  • SORT: メモリ内でのソーティング
  • LIMIT: 返り値の数を制限
  • SKIP: スキップして使用
  • IDHACK: _id のクエリ
  • SHARDING_FILTER: mongosを通じてシャード化されたデータをクエリ
  • COUNT: db.coll.explain().count()など、カウント操作を使用した場合
  • COUNTSCAN: カウントに非インデックスを使用していない場合のステージ
  • COUNT_SCAN: カウントにインデックスを使用している場合のステージ
  • SUBPLA: インデックスを使用していない$orクエリのステージ
  • TEXT: フルテキストインデックスを使用したクエリのステージ
  • PROJECTION: 返されるフィールドを制限するためのステージ

executionStatsコンテンツ

以下の内容は、executionStatsモードで返されるコンテンツで、非キー情報は無視します。

{
	"executionStats" : {
		"executionSuccess" : true,
		"nReturned" : 5,  // 返されたドキュメントの数
		"executionTimeMillis" : 0, // 実行時間
		"totalKeysExamined" : 0, // スキャンされたインデックスの数
		"totalDocsExamined" : 5, // スキャンされたドキュメントの合計数
		"executionStages" : {
			"stage" : "COLLSCAN", // ステージタイプ、COLLSCANはテーブル全体をスキャンすることを意味します
			"nReturned" : 5,
			"executionTimeMillisEstimate" : 0,
			"works" : 7,
			"advanced" : 5,
			"needTime" : 1,
			"needYield" : 0,
			"saveState" : 0,
			"restoreState" : 0,
			"isEOF" : 1,
			"direction" : "forward",
			"docsExamined" : 5
		}
	}
}

クエリの最適化アイデア

  • 可能な限りインデックスを使用する
  • スキャンされるドキュメント数をできるだけ少なくする