您可以使用解释结果,确定有关查询的以下信息:
完成查询所需的时间
查询是否使用索引
为完成查询而扫描的文档和索引键的数量
注意
查询的解释计划结果可能会在各个 MongoDB 版本之间发生变化。
cursor.explain("executionStats") 和 db.collection.explain("executionStats") 方法提供了有关查询性能的统计信息。这些统计信息可用于衡量查询是否索引以及是如何使用该索引的。有关详细信息,请参阅 db.collection.explain()。
评估查询性能
本页上的示例使用 sample_mflix 数据集中的数据。有关如何将此数据集加载到自管理MongoDB 部署中的详细信息,请参阅加载样本数据集。如果对示例数据库进行了任何修改,则可能需要删除并重新创建数据库才能运行本页上的示例。
本页上的示例使用 sample_mflix示例数据集中的数据。有关如何将此数据集加载到部署的详细信息,请参阅将样本数据导入到Atlas部署中。
加载数据集后,将MongoDB Compass连接到同一部署并打开 movies集合。
集合文档在MongoDB Compass中显示如下:

无索引查询
以下查询检索 year 字段的值在 2000 和 2005(含)之间的文档:
db.movies.find( { year: { $gte: 2000, $lte: 2005 } } )
此查询与集合中 21349 份文档的 3809 份匹配。
要查看选定的查询计划,请将 cursor.explain("executionStats") 游标方法链接到 find 命令的末尾:
db.movies.find( { year: { $gte: 2000, $lte: 2005 } } ).explain("executionStats")
{ queryPlanner: { namespace: 'sample_mflix.movies', winningPlan: { stage: 'COLLSCAN', '...': '...' }, '...': '...' }, executionStats: { executionSuccess: true, nReturned: 3809, totalKeysExamined: 0, totalDocsExamined: 21349, executionStages: { stage: 'COLLSCAN', '...': '...' }, '...': '...' }, '...': '...' }
queryPlanner.winningPlan.stage显示COLLSCAN,表示会进行集合扫描。集合扫描表明
mongod必须对整个集合的文档进行逐份扫描才能识别结果。此项操作通常成本高昂,可能会降低查询速度。executionStats.nReturned显示3809以表明获胜的查询计划返回 3,809 文档。executionStats.totalKeysExamined显示0,表示此查询未使用索引。executionStats.totalDocsExamined显示21349以指示MongoDB必须扫描集合中的所有 21,349 文档才能找到 3,809 匹配的文档。
以下查询检索 year 字段的值在 2000 和 2005(含)之间的文档:
将以下过滤器复制到 Compass 查询栏中,然后单击 Find:
{ year: { $gte: 2000, $lte: 2005 } }
此查询与集合中 21349 份文档的 3809 份匹配。
要查看查询计划,请单击查询栏中的 Explain。
MongoDB Compass 显示查询计划,如下所示:

可视化树
Query Performance Summary 显示查询的执行统计信息:
Documents Returned 显示
3809以表明获胜的查询计划返回 3,809 文档。Documents Examined 显示
21349以指示MongoDB必须扫描集合中的所有 21,349 文档才能找到 3,809 匹配文档。Index Keys Examined 显示
0表明该查询未使用索引。
MongoDB Compass显示
COLLSCAN查询阶段,表示此查询使用了集合扫描。集合扫描表明mongod必须逐个文档扫描整个集合文档才能识别结果。这通常是一项成本高昂的操作,可能会导致查询速度减慢。
Raw JSON
还可以通过单击 Raw Output 选项以原始JSON格式查看 Explain Plan 详细信息:

匹配文档和已检查文档之间的数量差异可能表明,使用索引可能有助于提高查询效率。
带索引的查询
要支持对 year 字段的查询,请对 year 字段添加索引:
db.movies.createIndex( { year: 1 } )
要查看查询计划的统计信息,请使用 explain() 方法:
db.movies.find( { year: { $gte: 2000, $lte: 2005 } } ).explain("executionStats")
{ queryPlanner: { namespace: 'sample_mflix.movies', winningPlan: { stage: 'FETCH', inputStage: { stage: 'IXSCAN', keyPattern: { year: 1 }, '...': '...' }, '...': '...' }, '...': '...' }, executionStats: { executionSuccess: true, nReturned: 3809, totalKeysExamined: 3809, totalDocsExamined: 3809, '...': '...' }, '...': '...' }
queryPlanner.winningPlan.inputStage.stage显示IXSCAN,表示使用索引。executionStats.nReturned显示3809以表明获胜的查询计划返回 3,809 文档。executionStats.totalKeysExamined显示3809,表示MongoDB已扫描 3、809索引项。检查的键数量与返回的文档数量相匹配,这意味着mongod只需要检查索引键即可返回结果。mongod不必扫描所有文档,只需将 3,809 匹配的文档拉入内存。这样查询就非常高效。executionStats.totalDocsExamined显示3809以指示MongoDB扫描了 3、809 文档。
要支持对 year 字段的查询,请对 year 字段添加索引:
单击
sample_mflix.movies集合的Indexes标签页。单击 Create,然后从下拉菜单中选择 Index。
从 Select or type a field name 下拉列表中选择
year。从 Select a type 下拉列表中选择
1 (asc)。单击 Create Index(连接)。
注意
将索引名称字段留空会导致 MongoDB Compass 为索引创建默认名称。
现在,您可以在 Indexes 标签页中看到新创建的索引:

返回到 sample_mflix.movies 集合的 Documents 标签页,然后重新运行上一步中的查询:
{ year: { $gte: 2000, $lte: 2005 } }
打开 Explain Plan 模态窗口。 MongoDB Compass 显示查询计划,如下所示:

可视化树
Query Performance Summary 显示查询的执行统计信息:
Documents Returned 显示
3809以表明获胜的查询计划返回 3,809 文档。Documents Examined 显示
3809以表明MongoDB已扫描 3、809 文档。在 Query Performance Summary 的底部, MongoDB Compass显示该查询使用了
year索引。
在 Query Performance Summary 的左侧, MongoDB Compass显示查询阶段
FETCH和IXSCAN。IXSCAN表示mongod在执行FETCH阶段并检索文档之前使用索引来满足查询。
Raw JSON
还可以通过单击 Raw Output 选项以原始JSON格式查看解释详细信息:

如果没有索引,查询将扫描整个集合以返回匹配的文档。查询还必须扫描每个文档的整体,可能会将它们拉入内存。这会导致查询操作成本高昂且可能缓慢。
使用索引运行时,查询仅扫描返回的索引项和文档,从而提高查询效率。
比较索引性能
如要手动比较使用多个索引的查询性能,您可以结合使用 hint() 方法和 explain() 方法。
考虑以下查询:
db.movies.find( { year: { $gte: 2000, $lte: 2005 }, rated: "PG" } )
此查询匹配 235 文档。
为支持查询,请添加复合索引。在复合索引中,字段的顺序很重要。
例如,添加以下两个复合索引。第一个索引首先按 year 字段排序,然后按 rated 字段排序。第二个索引首先按 rated 排序,然后按 year 字段排序。
db.movies.createIndex( { year: 1, rated: 1 } ) db.movies.createIndex( { rated: 1, year: 1 } )
评估第一个索引对查询的影响:
db.movies.find( { year: { $gte: 2000, $lte: 2005 }, rated: "PG" } ).hint( { year: 1, rated: 1 } ).explain("executionStats")
{ queryPlanner: { namespace: 'sample_mflix.movies', winningPlan: { stage: 'FETCH', inputStage: { stage: 'IXSCAN', keyPattern: { year: 1, rated: 1 }, '...': '...' }, '...': '...' }, '...': '...' }, executionStats: { executionSuccess: true, nReturned: 235, totalKeysExamined: 246, totalDocsExamined: 235, '...': '...' }, '...': '...' }
MongoDB扫描了246个索引键 (executionStats.totalKeysExamined) 以返回 235 个匹配的文档 (executionStats.nReturned)。
评估第二个索引对查询的影响:
db.movies.find( { year: { $gte: 2000, $lte: 2005 }, rated: "PG" } ).hint( { rated: 1, year: 1 } ).explain("executionStats")
{ queryPlanner: { namespace: 'sample_mflix.movies', winningPlan: { stage: 'FETCH', inputStage: { stage: 'IXSCAN', keyPattern: { rated: 1, year: 1 }, '...': '...' }, '...': '...' }, '...': '...' }, executionStats: { executionSuccess: true, nReturned: 235, totalKeysExamined: 235, totalDocsExamined: 235, '...': '...' }, '...': '...' }
MongoDB扫描了235个索引键 (executionStats.totalKeysExamined) 以返回 235 个匹配的文档 (executionStats.nReturned)。
因此,第二个复合索引{ rated: 1, year: 1 } 是支持示例查询的更有效索引,因为MongoDB服务器只需扫描 235 index keys 即可使用此索引查找所有匹配的文档,而 246 则使用此索引使用复合索引{ year: 1, rated: 1 }。