使用explain()查看mongodb查询语句的执行计划

与mysql, oracle等关系数据库类似,mongodb通过查询优化器,为每一个查询语句计算出最优的查询计划, 包括选择的索引, 查询时间,扫描的记录,扫描的索引数量,备选执行计划等信息。本文介绍使用explain()查看单个查询语句的执行计划。

explain() 语法

使用explain()获取查询语句的查询计划。语法如下

javascript 复制代码
db.collections.explain().<method(...)>

如查看db.orders.find()的执行计划

javascript 复制代码
db.orders.explain().find()

{
	"explainVersion" : "2",
	"queryPlanner" : {
		"namespace" : "meituan.orders",
		"indexFilterSet" : false,
		"parsedQuery" : {
			
		},
		"queryHash" : "E475932B",
		"planCacheKey" : "66AC8600",
		"maxIndexedOrSolutionsReached" : false,
		"maxIndexedAndSolutionsReached" : false,
		"maxScansToExplodeReached" : false,
		"winningPlan" : {
			"queryPlan" : {
				"stage" : "COLLSCAN",
				"planNodeId" : 1,
				"filter" : {
					
				},
				"direction" : "forward"
			},
			"slotBasedPlan" : {
				"slots" : "$$RESULT=s4 env: { s1 = TimeZoneDatabase(Antarctica/Rothera...Antarctica/Vostok) (timeZoneDB), s3 = 1699514675958 (NOW), s2 = Nothing (SEARCH_META) }",
				"stages" : "[1] scan s4 s5 none none none none lowPriority [] @\"8e5238a3-24a2-4d90-ba2c-34c78b61f5ea\" true false "
			}
		},
		"rejectedPlans" : [ ]
	},
	"command" : {
		"find" : "orders",
		"filter" : {
			
		},
		"batchSize" : 1000,
		"projection" : {
			
		},
		"$readPreference" : {
			"mode" : "primary"
		},
		"$db" : "meituan"
	},
	"serverInfo" : {
		"host" : "XXXXXX-W11",
		"port" : 27017,
		"version" : "7.0.1",
		"gitVersion" : "425a0454d12f2664f9e31002bbe4a386a25345b5"
	},
	"serverParameters" : {
		"internalQueryFacetBufferSizeBytes" : 104857600,
		"internalQueryFacetMaxOutputDocSizeBytes" : 104857600,
		"internalLookupStageIntermediateDocumentMaxSizeBytes" : 104857600,
		"internalDocumentSourceGroupMaxMemoryBytes" : 104857600,
		"internalQueryMaxBlockingSortMemoryUsageBytes" : 104857600,
		"internalQueryProhibitBlockingMergeOnMongoS" : 0,
		"internalQueryMaxAddToSetBytes" : 104857600,
		"internalDocumentSourceSetWindowFieldsMaxMemoryBytes" : 104857600,
		"internalQueryFrameworkControl" : "trySbeEngine"
	},
	"ok" : 1
}

explain() 的三种输出模式

explain()默认按照queryPlanner 返回执行计划的内容。除了queryPlanner模式,还有executionStats模式和allPlansExecution模式。三种模式使用方法如下。

  • 默认(queryPlanner)模式
javascript 复制代码
db.collection.explain().find()
db.collection.explain("queryPlanner").find()
  • executionStats 模式
javascript 复制代码
db.collection.explain("executionStatus").find()
  • allPlansExecution模式
javascript 复制代码
db.collection.explain("allPlansExecution").find()

三种模式返回的内容不同。 queryPlanner返回查询优化器中选择的执行计划,如数据查询方式,全表扫描COLLSCAN,索引扫描IXSCAN等。在选择使用索引查询时,返回查询时所需要的索引。"executionStats"模式下,除了返回执行计划外,还返回按照执行计划查询的执行信息,包括执行时间,扫描索引的数量,扫描文档的数量,每个查询阶段的执行信息。"allPlanExecution"模式,除执行计划和执行信息外,还包执行计划选择期间所有执行计划的统计信息,包括备选方案的执行统计信息。通过查看执行计划,可以查看数据库是否按照预期的方案执行,给出数据库查询优化方案。如添加hint(), 删除或添加索引,修改索引定义方式等来提高查询效率。

Explain() 使用场景

explain()适用于下面几种查询和数据更新语句。

  • aggregate()
  • find()
  • distinct()
  • count()
  • remove()
  • findAndModify()
  • group()
  • update()
  • mapReduce()

对于数据更新的语句remove(), findAndModify(), update(), 添加explain()后,数据更新语句并不会真正的执行,只是返回查询时使用的执行计划。

Aggregation中包含out, merge语句时,只能用默认模式,即queryPlanner模式,不可以使用executionStats模式和allPlansExecution模式。

explain()使用时,需要置于查询或更新的语句前面。

db.collection.explain().find()和db.collection.find().explain()两个查询语句不同。db.collection.explain().find()在查询链中还可以添加更多的查询修饰语句。

如 db.collection.explain().find().limit(1)

Db.collection.explain().find().count().hint()等

db.collection.find().explain()返回查询执行计划的cursor,需要使用next()获取执行计划。后续不可以再添加查询修饰语句。

使用db.collection.explain().help()获取explain的更多使用方法和帮助信息

javascript 复制代码
db.order.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
	.group(...) - explain a group operation
	.mapReduce(...) - explain a mapReduce operation
	.remove(...) - explain a remove operation
	.update(...) - explain an update operation
Explainable collection methods
	.getCollection()
	.getVerbosity()
	.setVerbosity(verbosity)

使用db.collection.explain().find().help()获取查询修饰符和explain的cursor信息。

javascript 复制代码
db.order.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)

explain() 实现机制

实现上,explain()封装了mongodb explain命令

javascript 复制代码
  db.runCommand(
 {
     explain: <command>,
     verbosity: <string>,
     comment: <any>
   }
)

javascript 复制代码
db.runCommand(
   {
     explain: { count: "products", query: { quantity: { $gt: 50 } } },
     verbosity: "queryPlanner"
   }
)

比较explain() 与$indexStats

两个命令都可以用于查看集合中定义的索引和执行信息。 但两个命令各有侧重点,使用场景也不用。

explain()返回查询语句的执行计划,包含数据扫描方式, 全表扫描(COLLSCAN),索引扫描(IXSCAN)等, 还包括查询语句的执行时间,扫描文档的数量,扫描索引key的数量等。通过explain(),技术人员可以发现查询是否需要添加索引,或者对已有索引进行修改,或增加hint()在引导查询优化器选用更好的执行计划。针对单个查询进行优化。

$indexStatus, 统计单个集合中所有索引定义和使用情况。包含索引定义的详细信息,索引的命中信息等。针对使用较少的索引,可以进行优化。

实际运用中,需要结合使用explain()和$indexStats两者的返回结果。

相关推荐
rrrjqy4 分钟前
Redis常见问题(一)
数据库·redis·缓存
Humbunklung5 分钟前
WMO 天气代码(Code Table 4677)深度解析与应用报告
开发语言·数据库·python
道清茗15 分钟前
【MySQL知识点问答题】锁机制、索引优化与数据库恢复方法
数据库·mysql
hero.fei27 分钟前
排查redis出现报错ERR redis temporary failure
数据库·redis·缓存
野犬寒鸦36 分钟前
MySQL复习记录Day01
数据库·后端
ward RINL41 分钟前
Spring boot启动原理及相关组件
数据库·spring boot·后端
RisunJan1 小时前
Linux命令-mysqldump(MySQL数据库中备份工具)
linux·数据库·mysql
DolphinDB智臾科技1 小时前
直播回顾 | 物联网时序数据库如何驱动电力场景智能调度?
数据库·物联网·时序数据库
郝学胜-神的一滴1 小时前
解锁CS数据存储的核心逻辑:从结构选择到表单设计的全解析
linux·服务器·数据库·c++·后端·oracle
qq_391105341 小时前
TDengine C# 连接示例和授权管理
大数据·数据库·c#·时序数据库·tdengine