1 执行计划概述
通过执行计划我们可以观察系统如何使用索引来加快检索,同时可以做针对性的性能优化。
explain结果将查询计划以阶段树的形式呈现。每个阶段将其结果(文档或索引键)传递给父节点。叶节点访问集合或索引。中间节点操纵有子节点产生的文档或索引建。根节点是mongodb从中派生结果集的最后阶段。
在MongoDB 中,可以通过explain命令来查看其它命令的执行信息,比如:aggregate, count, distinct, find, findAndModify, delete, mapReduce, update。
示例:
db.runCommand(
{
explain: { count: "products", query: { quantity: { $gt: 50 } } },
verbosity: "queryPlanner"
}
)
Explain命令的详细说明可以参考官方手册:
https://www.mongodb.com/docs/v4.4/reference/command/explain/
虽然可以使用explain 命令来查看执行计划,但是MongoDB 官方更建议使用db.collection.explain() 和cursor.explain()方法来查看执行计划。 本质上db.collection.explain()方法也是对explain 命令的封装。
到了MongoDB 4.4 版本,db.collection.explain() 支持的方法已经和explain命令相同。 所以可以完全替代explain 命令。
官网的说明如下:
db.collection.explain()
https://www.mongodb.com/docs/v4.4/reference/method/db.collection.explain/
cursor.explain()
https://www.mongodb.com/docs/v4.4/reference/method/cursor.explain/
2 执行计划的三种模式
db.collection.explain()方法的语法格式如下:
db.collection.explain().
比如:
db.products.explain().remove( { category: “apparel” }, { justOne: true } )
也可以通过帮助查看:
mongos> db.collection.explain().help()
Explainable operations
.aggregate(...) - explain an aggregation operation
.count(...) - explain a count operation
.distinct(...) - explain a distinct operation
.find(...) - get an explainable query
.findAndModify(...) - explain a findAndModify operation
.mapReduce(...) - explain a mapReduce operation
.remove(...) - explain a remove operation
.update(...) - explain an update operation
Explainable collection methods
.getCollection()
.getVerbosity()
.setVerbosity(verbosity)
mongos>
mongos> db.collection.explain().find().help()
Explain query methods
.finish() - sends explain command to the server and returns the result
.forEach(func) - apply a function to the explain results
.hasNext() - whether this explain query still has a result to retrieve
.next() - alias for .finish()
Explain query modifiers
.addOption(n)
.batchSize(n)
.comment(comment)
.collation(collationSpec)
.count()
.hint(hintSpec)
.limit(n)
.maxTimeMS(n)
.max(idxDoc)
.min(idxDoc)
.readPref(mode, tagSet)
.showDiskLoc()
.skip(n)
.sort(sortSpec)
mongos>
db.collection.explain()方法有一个可选的参数:verbosity。该参数会影响到 explain()方法的行为和返回的信息,可以设置为如下3个值:
- “queryPlanner” (Default)
- “executionStats”
- “allPlansExecution”
2.1 “queryPlanner” (Default) 模式
默认情况下,db.collection.explain() 运行在queryPlanner 模式。
MongoDB通过查询优化器对待评估操作来选择最佳的查询计划(winning plan)。db.collection.explain() 返回评估方法(evaluated method)的查询计划(queryPlanner)信息。
2.2 “executionStats” 模式
MongoDB 通过查询优化器(query optimizer) 选择最佳的执行计划,然后执行该计划,待该计划执行完成后,返回描述最佳计划执行情况的统计信息。
对于写操作,db.collection.explain() 会返回待执行的update和delete 操作信息,但不会将这些修改应用到数据库。
db.collection.explain() 返回评估方法(evaluated method)的queryPlanner 和 executionStats信息。对于非最优的执行计划(rejected plans),executionStats 不会提供查询执行信息。
2.3 “allPlansExecution” 模式
MongoDB 通过查询优化器(query optimizer) 选择最佳的执行计划,然后执行该计划。 在allPlansExecution 模式下,MongoDB 除了返回描述最佳计划执行情况的统计信息,还返回在计划选择期间捕获的其他候选计划的统计信息。
同样,对于写操作,db.collection.explain() 会返回待执行的update和delete 操作信息,但不会将这些修改应用到数据库。
db.collection.explain() 返回评估方法(evaluated method)的queryPlanner 和 executionStats信息。对于最优执行计划(winning plan),executionStats包含完整的查询执行信息。
如果查询优化器分析了多个计划,executionStats信息还包括计划选择阶段最优计划和非最优计划的部分执行信息。
2.4 使用示例
db.products.explain().count( { quantity: { $gt: 50 } } )
db.products.explain("executionStats").find(
{ quantity: { $gt: 50 }, category: "apparel" }
)
db.products.explain("allPlansExecution").update(
{ quantity: { $lt: 1000}, category: "apparel" },
{ $set: { reorder: true } }
)
db.products.explain("executionStats").find(
{ quantity: { $gt: 50 }, category: "apparel" }
).sort( { quantity: -1 } ).hint( { category: 1, quantity: -1 } )
3 返回结果说明
返回结果官网有详细说明,可以直接查看:
Explain Results
https://www.mongodb.com/docs/v4.4/reference/explain-results/
这里主要需要关注4个选项:
- “nReturned” : 查询条件匹配到的文档数量,即操作返回的数据量。
- “executionTimeMillisEstimate” : 查询计划所需的总时间(毫秒为单位)
- “totalKeysExamined” : 扫描的索引项数(索引扫描条目)。
- “totalDocsExamined” : 扫描的文档数,而不是返回的文档数。如果在查询执行期间多次检查文档,则totalDocsExamined会对每次检查进行计数。也就是说,totalDocsExamined不是检查的唯一文档总数的计数。
检查文档常用的查询执行阶段是COLLSCAN和FETCH。
执行计划中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的返回
对于普通查询,希望看到stage的组合(查询的时候尽可能用上索引):
- Fetch + IDHACK
- Fetch + ixscan
- Limit+(Fetch + ixscan)
- PROJECTION + ixscan
- SHARDING_FITER + ixscan
- COUNT_SCAN
不希望看到包含如下的stage:
- COLLSCAN(全表扫描)
- SORT(使用sort但是无index)
- 不合理的SKIP,SUBPLA(未用到index的$or)
- COUNTSCAN(不使用index进行count)
更多案例可以参考:
https://blog.csdn.net/mijichui2153/article/details/115680742
版权声明:本文为博主原创文章,未经博主允许不得转载。