在 Mongoose 中使用 MongoDB Explain 解释查询
在 MongoDB 中, explain
command 告诉 MongoDB 服务器返回有关它如何执行查询的统计信息,而不是查询的结果。 Mongoose 查询 有一个 explain()
将查询转换为 explain()
。
const Character = mongoose.model('Character', mongoose.Schema({
name: String,
age: Number,
rank: String
}));
await Character.create([
{ name: 'Jean-Luc Picard', age: 59, rank: 'Captain' },
{ name: 'William Riker', age: 29, rank: 'Commander' },
{ name: 'Deanna Troi', age: 28, rank: 'Lieutenant Commander' },
{ name: 'Geordi La Forge', age: 29, rank: 'Lieutenant' },
{ name: 'Worf', age: 24, rank: 'Lieutenant' }
]);
const explain = await Character.find({ name: /Picard/ }).explain().
then(res => res[0]);
// Object describing how MongoDB planned to execute the query
explain.queryPlanner;
// Object containing stats about how MongoDB executed the query
explain.executionStats;
阅读 queryPlanner
输出
这 queryPlanner
对象包含有关 MongoDB 如何决定执行查询的更多详细信息。 例如,下面是 queryPlanner
从上面的对象 explain()
称呼。
{
plannerVersion: 1,
namespace: 'test.characters',
indexFilterSet: false,
parsedQuery: { name: { '$regex': 'Picard' } },
winningPlan: {
stage: 'COLLSCAN',
filter: { name: { '$regex': 'Picard' } },
direction: 'forward'
},
rejectedPlans: []
}
最重要的信息是 winningPlan
属性,它包含有关 MongoDB 决定执行查询的计划的信息。 在实践中, winningPlan
对于检查 MongoDB 是否使用索引进行查询很有用。
查询计划 是用于识别与查询匹配的文档的阶段列表 上面的计划只有一个阶段,COLLSCAN,这意味着 MongoDB 执行了一次完整的集合扫描来回答查询。
集合扫描意味着 MongoDB 搜索“字符”集合中的每个文档以查看是否 name
匹配给定的查询。 当您引入索引时,查询计划会变得更加复杂。 例如,假设您在 name
如下所示。
await Character.collection.createIndex({ name: 1 });
const explain = await Character.find({ name: 'Jean-Luc Picard' }).explain().
then(res => res[0]);
// Object describing how MongoDB planned to execute the query
explain.queryPlanner;
这 queryPlanner
输出如下所示:
{
plannerVersion: 1,
namespace: 'test.characters',
indexFilterSet: false,
parsedQuery: { name: { '$eq': 'Jean-Luc Picard' } },
winningPlan: {
stage: 'FETCH',
inputStage: {
stage: 'IXSCAN',
keyPattern: { name: 1 },
indexName: 'name_1',
isMultiKey: false,
multiKeyPaths: { name: [] },
isUnique: false,
isSparse: false,
isPartial: false,
indexVersion: 2,
direction: 'forward',
indexBounds: { name: [ '["Jean-Luc Picard", "Jean-Luc Picard"]' ] }
}
},
rejectedPlans: []
}
这 winningPlan
属性是一个递归结构: winningPlan
指向获胜查询计划的最后一个阶段,每个阶段都有一个 inputStage
描述前一阶段的属性。 在上述计划中,有两个阶段:IXSCAN 和FETCH。 这意味着第一个 MongoDB 使用 { name: 1 }
索引来识别哪些文档与查询匹配,然后获取各个文档。
阅读 executionStats
输出
这 executionStats
输出比 queryPlanner
:它包括关于每个阶段花费了多长时间以及每个阶段扫描了多少文件的统计信息。
例如,下面是 executionStats
简单集合扫描的输出:
{
executionSuccess: true,
nReturned: 1,
executionTimeMillis: 0,
totalKeysExamined: 0,
totalDocsExamined: 5,
executionStages: {
stage: 'COLLSCAN',
filter: { name: { '$regex': 'Picard' } },
nReturned: 1,
executionTimeMillisEstimate: 0,
works: 7,
advanced: 1,
needTime: 5,
needYield: 0,
saveState: 0,
restoreState: 0,
isEOF: 1,
direction: 'forward',
docsExamined: 5
},
allPlansExecution: []
}
这里要注意的重要细节是顶层 executionTimeMillis
和 totalDocsExamined
特性。 executionTimeMillis
是 MongoDB 执行查询所花费的时间,以及 totalDocsExamined
是 MongoDB 为回答查询而必须查看的文档数量。
请记住, executionTimeMillis
不 所 包括网络延迟或 花费的时间 。 只是因为 executionTimeMillis
小并不意味着最终用户可以立即看到结果。 当你有一个索引和多个阶段时, executionStats
分解每个阶段的大致执行时间和扫描的文档数量。
下面是 executionStats
对于带有索引的查询,为简洁起见,排除了一些不太重要的细节:
{
executionSuccess: true,
nReturned: 1,
executionTimeMillis: 2,
totalKeysExamined: 1,
totalDocsExamined: 1,
executionStages: {
stage: 'FETCH',
nReturned: 1,
executionTimeMillisEstimate: 0,
// ...
docsExamined: 1,
// ...
inputStage: {
stage: 'IXSCAN',
nReturned: 1,
executionTimeMillisEstimate: 0,
// ...
}
},
allPlansExecution: []
}
以上 executionStats
输出表明有两个阶段:IXSCAN 和 FETCH。 IXSCAN 阶段在 0 毫秒内执行并导致一个文档被发送到 FETCH 阶段。 FETCH 阶段检查了 1 个文档,并返回了 1 个文档,这是查询的最终结果。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论