概要
MongoDB 3.0 からexplainの結果が大きく変わりました。
スロークエリを調べる上で、インデックスの使用、外部ソートの使用などをどこで確認するかをまとめてみました。
環境
- Ubuntu 14.04
- MongoDB 3.0.4
大まかな構造(全体)
> db.users.find({name: "ユーザ001"}).explain() { "queryPlanner" : { "plannerVersion" : 1, "namespace" : "コレクション", "indexFilterSet" : false, "parsedQuery" : { // findの中のクエリ }, "winningPlan" : { // 採用されたインデクス }, "rejectedPlans" : [ // インデクスとして使えるが、今回は使われなかったインデクス ] }, "serverInfo" : { // サーバ情報 }, "ok" : 1 }
上記のようにqueryPlannerに詳細が出てきます。
主にwinningPlanを見ます。
大まかな構造(プラン)
winningPlanの中身を以下に表示します。
"stage": "FETCH", "inputStage": { "stage": "IXSCAN", "filter": { "name": {} }, "keyPattern": { "name": 1 }, "indexName": "name_1", "isMultiKey": false, "direction": "forward", "indexBounds": { "name": [ "[\"\", {})", "[/ユーザ001/, /ユーザ001/]" ] } }
Mongo3.0ではstageというものでインデクスを使用しているか判断します。
よく見るstageは以下です。
| 種類 | 意味 |
|---|---|
| COLLSCAN | インデクスを用いないフルスキャン |
| IXSCAN | インデクスを用いたスキャン |
| FETCH | コレクションからドキュメントを取得 |
| SHARD_MERGE | シャードから結果を集約 |
| LIMIT | limitで件数制限 |
簡単に言ってしまえば、IXSCANであればインデクスを使っています。
なので最低限そこは注意しましょう。
またstageはクエリによってはネストした親子関係になります。
上の例の場合は「インデクスでスキャン後、コレクションからドキュメント取得」なので、
FETCH └IXSCAN
となってます。
これに更に.limit()をつければ「インデクスでスキャン後、コレクションからドキュメント取得し、件数を制限」するので
LIMIT └FETCH └IXSCAN
となります。
応用
「外部ソートを使用しているか」、「クエリプランは最適か」など、更に詳細を調べたい場合はexecutionStatsを付けます。
> db.users.find({name: "ユーザ001"}).explain("executionStats")
先ほどのフィールドに加えてより詳細なフィールドが表示されます。
簡単のためよく見るフィールドのみ以下に書きます。
"executionStats" : { ..., "nReturned" : 1, "totalKeysExamined" : 1, "totalDocsExamined" : 1, ..., },
上記の意味の説明と、旧バージョンを比較した表が以下です。
| 3.0 | 2.6 | 説明 |
|---|---|---|
| totalKeysExamined | nscanned | スキャンされたドキュメントの数 |
| totalDocsExamined | nscannedObjects | コレクションから取得したドキュメント数 covered queriesなら 0になる |
| nReturned | n | 最終的に返却したドキュメント数 |
| stage: "SORT" | scanAndOrder: true | 外部ソートを使用 |
IXSCANの親stageがFETCHでない |
indexOnly: true | Covered Queries |
これらをチェックすれば基本的に大丈夫です。