MongoDB运行查询优化器以选择获胜计划并执行获胜计划以完成。 在"allPlansExecution"模式中,MongoDB返回描述获胜计划执行情况的统计信息以及计划选择期间捕获的其他候选计划的统计信息。对于写入操作, db.collection.explain()返回有关将执行的更新或删除操作的信息,但不会将修改应用于数据库。db.collection.explain()返回已计算方法的queryPlanner和executionStats信息。 executionStats包括获胜计划的完整查询执行信息。如果查询优化器考虑了多个计划,则executionStats信息还包括在计划选择阶段为获胜和被拒绝的候选计划捕获的部分执行信息。
1.限制
从MongoDB 4.2开始,您无法在executionStats模式 或 allPlansExecution模式下运行包含$out阶段的aggregation pipeline的explain命令/ db.collection.explain() 。 相反,您可以:
a.在queryPlanner模式下运行explain
b.在executionStats模式或allPlansExecution模式下运行explain但没有out阶段返回out阶段之前的阶段的信息。
2.explain() Mechanics
db.collection.explain()方法包装explain命令,是运行explain的首选方法。
db.collection.explain().find()类似于db.collection.find().explain()具有以下主要区别:
a.db.collection.explain().find()构造允许查询修饰符的附加链接。 有关查询修饰符的列表,请参阅db.collection.explain().find().help().
b.db.collection.explain().find()返回一个游标,它需要调用.next()或其别名.finish()来返回explain()结果。 如果在mongo shell中以交互方式运行, mongo shell会自动调用.finish()来返回结果。 但是,对于脚本,必须显式调用.next()或.finish()来返回结果。 有关与游标相关的方法的列表,请参阅db.collection.explain().find().help().
db.collection.explain().aggregate()等效于将explain选项传递给db.collection.aggregate()方法。
3.help()
要查看db.collection.explain()支持的操作列表,请运行:
db.collection.explain().help()
db.collection.explain().find()返回一个游标,允许链接查询修饰符。 要查看db.collection.explain().find()以及与游标相关的方法支持的查询修饰符列表,请运行:
db.collection.explain().find().help()
您可以将多个修饰符链接到db.collection.explain().find()
4.示例
(1).queryPlanner模式
默认情况下, db.collection.explain()以"queryPlanner"详细模式运行。
以下示例在"queryPlanner"详细模式下运行db.collection.explain()以返回指定count()操作的查询计划信息:
db.products.explain().count( { quantity: { $gt: 50 } } )
(2).executionStats模式
以下示例在"executionStats"详细模式下运行db.collection.explain() ,以返回指定find()操作的查询计划和执行信息:
db.products.explain("executionStats").find(
{ quantity: { $gt: 50 }, category: "apparel" }
)
(3).allPlansExecution模式
以下示例在"allPlansExecution"详细模式下运行db.collection.explain() 。 db.collection.explain()为指定的update()操作的所有考虑的计划返回queryPlanner和executionStats :
注意:执行此解释不会修改数据,而是运行更新操作的查询谓词。 对于候选计划,MongoDB返回在计划选择阶段捕获的执行信息。
db.products.explain("allPlansExecution").update(
{ quantity: { $lt: 1000}, category: "apparel" },
{ $set: { reorder: true } }
)
(4).带修饰符find()的执行计划
db.collection.explain().find()构造允许链接查询修饰符。 例如,以下操作使用sort()和hint()查询修饰符提供有关find()方法的信息。
db.products.explain("executionStats").find(
{ quantity: { $gt: 50 }, category: "apparel" }
).sort( { quantity: -1 } ).hint( { category: 1, quantity: -1 } )
有关可用的查询修饰符列表,请在mongo shell中运行:
db.collection.explain().find().help()
(5).迭代explain().find()返回游标
db.collection.explain().find()将光标返回到解释结果。 如果在mongo shell中以交互方式运行, mongo shell将使用.next()方法自动迭代游标。 但是,对于脚本,您必须显式调用.next() (或其别名.finish() )以返回结果:
var explainResult = db.products.explain().find( { category: "apparel" } ).next();
5.db.collection.explain()操作可以返回有关以下内容的信息:
queryPlanner ,详细说明查询优化器选择的计划并列出被拒绝的计划;
executionStats ,详细说明获胜计划的执行情况和被拒绝的计划;
serverInfo ,提供有关MongoDB实例的信息。
详细模式(即queryPlanner , executionStats , allPlansExecution )确定结果是否包含executionStats以及executionStats是否包括在计划选择期间捕获的数据。
6.强制走索引hint()
要强制 MongoDB使用特定索引进行db.collection.find()操作,请使用hint()方法指定索引。 将hint()方法附加到find()方法。 请考虑以下示例:
db.people.find(
{ name: "John Doe", zipcode: { $gt: "63000" } }
).hint( { zipcode: 1 } )
要查看特定索引的执行统计信息,请将db.collection.find()附加到hint()方法后跟cursor.explain() ,例如:
db.people.find(
{ name: "John Doe", zipcode: { $gt: "63000" } }
).hint( { zipcode: 1 } ).explain("executionStats")
或者,将hint()方法附加到db.collection.explain().find() :
db.people.explain("executionStats").find(
{ name: "John Doe", zipcode: { $gt: "63000" } }
).hint( { zipcode: 1 } )
为hint()方法指定$natural运算符以防止MongoDB使用任何索引:
db.people.find(
{ name: "John Doe", zipcode: { $gt: "63000" } }
).hint( { $natural: 1 } )
7.索引指标
8.格式的更改
从MongoDB 3.0开始, explain结果的格式和字段已从先前版本更改。 以下列出了一些主要差异。
(1).集合扫描与索引使用
如果查询计划程序选择了集合扫描,则说明结果包括COLLSCAN阶段。
如果查询规划器选择索引,则解释结果包括IXSCAN阶段。 该阶段包括诸如索引键模式,遍历方向和索引边界之类的信息。
在以前版本的MongoDB中, cursor.explain()返回了cursor字段,其值为:
a.用于集合扫描的BasicCursor
b.索引扫描的BtreeCursor <index name> [<direction>]
有关集合扫描与索引扫描的执行统计信息的详细信息,请参阅分析查询性能 。Analyze Query Performance.
(2).覆盖查询
当索引覆盖查询时,MongoDB可以匹配查询条件并仅使用索引键返回结果; 即MongoDB不需要检查集合中的文档以返回结果。
当索引覆盖查询时,解释结果的IXSCAN阶段不是 FETCH阶段的后代,而在executionStats中 , totalDocsExamined为0 。
在早期版本的MongoDB中, cursor.explain()返回indexOnly字段以指示索引是否覆盖了查询。
(3).索引交集
对于索引交集计划 ,结果将包括AND_SORTED阶段或AND_HASH阶段, inputStages包含详细说明索引的inputStages数组; 例如:
{
"stage" : "AND_SORTED",
"inputStages" : [
{
"stage" : "IXSCAN",
...
},
{
"stage" : "IXSCAN",
...
}
]
}
在以前版本的MongoDB中, cursor.explain()返回了cursor字段,其中包含索引交叉点的Complex Plan值。
(4).$or表达式
如果MongoDB使用$or表达式的索引,则结果将包含OR阶段, inputStages包含详细说明索引的inputStages数组; 例如:
{
"stage" : "OR",
"inputStages" : [
{
"stage" : "IXSCAN",
...
},
{
"stage" : "IXSCAN",
...
},
...
]
}
在cursor.explain()版本的MongoDB中, cursor.explain()返回了详细索引的clauses数组。
(5).排序阶段
如果MongoDB可以使用索引扫描来获取请求的排序顺序,则结果将不包括SORT阶段。 否则,如果MongoDB无法使用索引进行排序,则explain结果将包括SORT阶段。
在MongoDB 3.0之前, cursor.explain()返回scanAndOrder字段以指定MongoDB是否可以使用索引顺序返回排序结果。