Carpe Diem

備忘録

MongoDB 3.0 での explain

概要

MongoDB 3.0 からexplainの結果が大きく変わりました。
スロークエリを調べる上で、インデックスの使用、外部ソートの使用などをどこで確認するかをまとめてみました。

環境

大まかな構造(全体)

> 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

これらをチェックすれば基本的に大丈夫です。

ソース