深入学习MongoDB之索引与执行计划

mongodb索引
创建索引:
db.getCollection("test").ensureIndex({"name":1});
或者db.getCollection("test").createIndex({"name":1});

{
    "raw" : {
        "shard3/192.168.3.18:20004,192.168.3.3:10004" : {
            "createdCollectionAutomatically" : false,
            "numIndexesBefore" : 1,
            "numIndexesAfter" : 2,
            "ok" : 1.0,
            "$gleStats" : {
                "lastOpTime" : Timestamp(6577988859047444, 1),
                "electionId" : ObjectId("5b48c90f0000000000001c96")
            }
        }
    },
    "ok" : 1.0
}
索引创建成功;

查询索引状态
db.getCollection("test").getIndexes({"name":1});

[
    {
        "v" : 1,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "dev.test"
    },
    {
        "v" : 1,
        "key" : {
            "name" : 1.0
        },
        "name" : "name_1",
        "ns" : "dev.test"
    }
]

可以看到_id索引(默认的),和name索引

删除索引
db.getCollection("test").dropIndex({"name":1});
删除结果
{
    "raw" : {
        "shard3/192.168.3.18:20004,192.168.3.3:10004" : {
            "nIndexesWas" : 2,
            "ok" : 1.0,
            "$gleStats" : {
                "lastOpTime" : Timestamp(6577989129630384, 1),
                "electionId" : ObjectId("5b48c90f0000000000001c96")
            }
        }
    },
    "ok" : 1.0
}

再次查询
db.getCollection("test").getIndexes({"name":1});
[
    {
        "v" : 1,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "dev.test"
    }
]

索引删除成功;

再次创建索引,并查看执行计划;
db.getCollection("test").ensureIndex({"name":1});
db.getCollection("test").find({name:"张三"}).explain();
{
    "queryPlanner" : {
        "mongosPlannerVersion" : 1,
        "winningPlan" : {
            "stage" : "SINGLE_SHARD",
            "shards" : [
                {
                    "shardName" : "shard3",
                    "connectionString" : "shard3/192.168.3.18:20004,192.168.3.3:10004",
                    "serverInfo" : {
                        "host" : "8ef2e84b1b94",
                        "port" : 27017,
                        "version" : "3.2.0",
                        "gitVersion" : "45d947729a0315accb6d4f15a6b06be6d9c19fe7"
                    },
                    "plannerVersion" : 1,
                    "namespace" : "dev.test",
                    "indexFilterSet" : false,
                    "parsedQuery" : {
                        "name" : {
                            "$eq" : "张三"
                        }
                    },
                    "winningPlan" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "name" : 1.0
                            },

                            "indexName" : "name_1",
                            "isMultiKey" : false,
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 1,
                            "direction" : "forward",
                            "indexBounds" : {
                                "name" : [
                                    "[\"张三\", \"张三\"]"
                                ]
                            }
                        }
                    },
                    "rejectedPlans" : []
                }
            ]
        }
    },
    "ok" : 1.0
}

通过winningPlan的"stage" : "FETCH",可以判断使用了索引,
另外可以给explain添加参数,查看更多的执行计划;

db.getCollection("test").find({name:"张三"}).explain("executionStats");
{
    "queryPlanner" : {
        "mongosPlannerVersion" : 1,
        "winningPlan" : {
            "stage" : "SINGLE_SHARD",
            "shards" : [
                {
                    "shardName" : "shard3",
                    "connectionString" : "shard3/192.168.3.18:20004,192.168.3.3:10004",
                    "serverInfo" : {
                        "host" : "8ef2e84b1b94",
                        "port" : 27017,
                        "version" : "3.2.0",
                        "gitVersion" : "45d947729a0315accb6d4f15a6b06be6d9c19fe7"
                    },
                    "plannerVersion" : 1,
                    "namespace" : "dev.test",
                    "indexFilterSet" : false,
                    "parsedQuery" : {
                        "name" : {
                            "$eq" : "张三"
                        }
                    },
                    "winningPlan" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "name" : 1.0
                            },

                            "indexName" : "name_1",
                            "isMultiKey" : false,
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 1,
                            "direction" : "forward",
                            "indexBounds" : {
                                "name" : [
                                    "[\"张三\", \"张三\"]"
                                ]
                            }
                        }
                    },
                    "rejectedPlans" : []
                }
            ]
        }
    },
    "executionStats" : {
        "nReturned" : 2,
        "executionTimeMillis" : 1,
        "totalKeysExamined" : 2,
        "totalDocsExamined" : 2,

        "executionStages" : {
            "stage" : "SINGLE_SHARD",
            "nReturned" : 2,
            "executionTimeMillis" : 1,
            "totalKeysExamined" : 2,
            "totalDocsExamined" : 2,
            "totalChildMillis" : NumberLong(0),
            "shards" : [
                {
                    "shardName" : "shard3",
                    "executionSuccess" : true,
                    "executionStages" : {
                        "stage" : "FETCH",
                        "nReturned" : 2,
                        "executionTimeMillisEstimate" : 0,
                        "works" : 3,
                        "advanced" : 2,
                        "needTime" : 0,
                        "needYield" : 0,
                        "saveState" : 0,
                        "restoreState" : 0,
                        "isEOF" : 1,
                        "invalidates" : 0,
                        "docsExamined" : 2,
                        "alreadyHasObj" : 0,
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "nReturned" : 2,
                            "executionTimeMillisEstimate" : 0,
                            "works" : 3,
                            "advanced" : 2,
                            "needTime" : 0,
                            "needYield" : 0,
                            "saveState" : 0,
                            "restoreState" : 0,
                            "isEOF" : 1,
                            "invalidates" : 0,
                            "keyPattern" : {
                                "name" : 1.0
                            },
                            "indexName" : "name_1",
                            "isMultiKey" : false,
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 1,
                            "direction" : "forward",
                            "indexBounds" : {
                                "name" : [
                                    "[\"张三\", \"张三\"]"
                                ]
                            },
                            "keysExamined" : 2,
                            "dupsTested" : 0,
                            "dupsDropped" : 0,
                            "seenInvalidated" : 0
                        }
                    }
                }
            ]
        }
    },
    "ok" : 1.0
}
"executionStats"表示执行状态,
    totalKeysExamined表示用到的索引数,如果这个值为0,则说明未使用到索引,
    totalDocsExamined表示扫描的文档书
    
rejectedPlans代表弃用的索引,当前关于name的索引只有一个,所以弃用所以为null,
我们添加一个name和age的联合索引:
db.getCollection("test").ensureIndex({"name":1,"age":1});
在执行查询计划:
db.getCollection("test").find({name:"张三"}).explain("executionStats");
/* 1 */
{
    "queryPlanner" : {
        "mongosPlannerVersion" : 1,
        "winningPlan" : {
            "stage" : "SINGLE_SHARD",
            "shards" : [
                {
                    "shardName" : "shard3",
                    "connectionString" : "shard3/192.168.3.18:20004,192.168.3.3:10004",
                    "serverInfo" : {
                        "host" : "8ef2e84b1b94",
                        "port" : 27017,
                        "version" : "3.2.0",
                        "gitVersion" : "45d947729a0315accb6d4f15a6b06be6d9c19fe7"
                    },
                    "plannerVersion" : 1,
                    "namespace" : "dev.test",
                    "indexFilterSet" : false,
                    "parsedQuery" : {
                        "name" : {
                            "$eq" : "张三"
                        }
                    },
                    "winningPlan" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "name" : 1.0
                            },

                            "indexName" : "name_1",
                            "isMultiKey" : false,
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 1,
                            "direction" : "forward",
                            "indexBounds" : {
                                "name" : [
                                    "[\"张三\", \"张三\"]"
                                ]
                            }
                        }
                    },
                    "rejectedPlans" : [
                        {
                            "stage" : "FETCH",
                            "inputStage" : {
                                "stage" : "IXSCAN",
                                "keyPattern" : {
                                    "name" : 1.0,
                                    "age" : 1.0
                                },
                                "indexName" : "name_1_age_1",
                                "isMultiKey" : false,
                                "isUnique" : false,
                                "isSparse" : false,
                                "isPartial" : false,
                                "indexVersion" : 1,
                                "direction" : "forward",
                                "indexBounds" : {
                                    "name" : [
                                        "[\"张三\", \"张三\"]"
                                    ],
                                    "age" : [
                                        "[MinKey, MaxKey]"
                                    ]
                                }
                            }
                        }
                    ]
                }
            ]
        }
    },
    "executionStats" : {
        "nReturned" : 2,
        "executionTimeMillis" : 1,
        "totalKeysExamined" : 2,
        "totalDocsExamined" : 2,
        "executionStages" : {
            "stage" : "SINGLE_SHARD",
            "nReturned" : 2,
            "executionTimeMillis" : 1,
            "totalKeysExamined" : 2,
            "totalDocsExamined" : 2,
            "totalChildMillis" : NumberLong(0),
            "shards" : [
                {
                    "shardName" : "shard3",
                    "executionSuccess" : true,
                    "executionStages" : {
                        "stage" : "FETCH",
                        "nReturned" : 2,
                        "executionTimeMillisEstimate" : 0,
                        "works" : 4,
                        "advanced" : 2,
                        "needTime" : 0,
                        "needYield" : 0,
                        "saveState" : 0,
                        "restoreState" : 0,
                        "isEOF" : 1,
                        "invalidates" : 0,
                        "docsExamined" : 2,
                        "alreadyHasObj" : 0,
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "nReturned" : 2,
                            "executionTimeMillisEstimate" : 0,
                            "works" : 3,
                            "advanced" : 2,
                            "needTime" : 0,
                            "needYield" : 0,
                            "saveState" : 0,
                            "restoreState" : 0,
                            "isEOF" : 1,
                            "invalidates" : 0,
                            "keyPattern" : {
                                "name" : 1.0
                            },
                            "indexName" : "name_1",
                            "isMultiKey" : false,
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 1,
                            "direction" : "forward",
                            "indexBounds" : {
                                "name" : [
                                    "[\"张三\", \"张三\"]"
                                ]
                            },
                            "keysExamined" : 2,
                            "dupsTested" : 0,
                            "dupsDropped" : 0,
                            "seenInvalidated" : 0
                        }
                    }
                }
            ]
        }
    },
    "ok" : 1.0
}
发现了弃用索引;
可以使用hint()指定使用的索引:
db.getCollection("test").find({name:"张三"}).hint({name:1,age:1}).explain("executionStats");
必须注意的是hint字段的顺序必须和已创建的索引保持一致

一般情况下,mongodb会自动选择索引,不需要手动hint


Stage状态分析
stage 描述
COLLSCAN 全表扫描
IXSCAN 扫描索引
FETCH 根据索引去检索指定document
SHARD_MERGE 将各个分片返回数据进行merge
SORT 表明在内存中进行了排序
LIMIT 使用limit限制返回数
SKIP 使用skip进行跳过
IDHACK 针对_id进行查询
SHARDING_FILTER 通过mongos对分片数据进行查询
COUNT 利用db.coll.explain().count()之类进行count运算
COUNTSCAN count不使用Index进行count时的stage返回
COUNT_SCAN count使用了Index进行count时的stage返回
SUBPLA 未使用到索引的$or查询的stage返回
TEXT 使用全文索引进行查询时候的stage返回
PROJECTION 限定返回字段时候stage的返回






你可能感兴趣的:(mongodb)