使用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两者的返回结果。

相关推荐
明月看潮生17 分钟前
青少年编程与数学 02-007 PostgreSQL数据库应用 11课题、视图的操作
数据库·青少年编程·postgresql·编程与数学
阿猿收手吧!24 分钟前
【Redis】Redis入门以及什么是分布式系统{Redis引入+分布式系统介绍}
数据库·redis·缓存
奈葵28 分钟前
Spring Boot/MVC
java·数据库·spring boot
leegong2311136 分钟前
Oracle、PostgreSQL该学哪一个?
数据库·postgresql·oracle
中东大鹅42 分钟前
MongoDB基本操作
数据库·分布式·mongodb·hbase
夜光小兔纸1 小时前
Oracle 普通用户连接hang住处理方法
运维·数据库·oracle
兩尛3 小时前
订单状态定时处理、来单提醒和客户催单(day10)
java·前端·数据库
web2u3 小时前
MySQL 中如何进行 SQL 调优?
java·数据库·后端·sql·mysql·缓存
Elastic 中国社区官方博客4 小时前
使用 Elasticsearch 导航检索增强生成图表
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
小金的学习笔记4 小时前
RedisTemplate和Redisson的使用和区别
数据库·redis·缓存