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

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

explain()语法

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

db.collections.explain().<method(…)>

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

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)模式
db.collection.explain().find()
db.collection.explain(“queryPlanner”).find()
  • executionStats 模式
db.collection.explain(“executionStatus”).find()
  • allPlansExecution模式
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的更多使用方法和帮助信息

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信息。

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命令

  db.runCommand(
 {
     explain: <command>,
     verbosity: <string>,
     comment: <any>
   }
)

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

比较explain()与$indexStats

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

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

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

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

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
MongoDB 查询语句中的索引失效通常发生在以下几种情况下: 1. **不包含索引字段的查询**:如果你的查询条件中没有使用到索引字段,即使该字段有索引,MongoDB仍会全表扫描,这会导致索引失效。例如,`db.collection.find({ name: 'John' })`,如果name不是索引字段,将不会使用索引。 2. **反向查询**:对于某些索引(如升序或单向索引),如果查询条件是降序的或者尝试从大到小搜索,索引就无法提供帮助,导致索引失效。 3. **复杂查询**:使用 $nin、$not、$exists 等运算符,或者使用 $regex (正则表达式) 对字符串字段进行查询,可能导致索引无法直接应用,从而失效。 4. **嵌套查询**:当查询涉及嵌套的文档结构,并且嵌套路径没有对应的索引,MongoDB可能需要遍历整个集合,使得索引无法优化查询。 5. **索引类型限制**:某些查询操作(如 `$elemMatch` 或 `$all`)仅适用于特定类型的索引,如不匹配的索引类型将无法使用。 6. **更新和删除后**:如果数据被更新或删除,特别是如果更新后索引不再适用,那么针对旧数据的查询可能会导致索引失效。 要确保索引的有效利用,应该根据查询模式和数据结构选择合适的索引类型,并定期检查查询性能以发现问题。如果有索引失效的问题,可以尝试重新设计查询,或者为查询条件创建合适的索引。同时,使用MongoDB的`explain()`方法可以帮助分析查询执行计划,了解是否有效利用了索引。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

威赞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值