explain()
explain()能够提供大量与查询相关的信息。对于速度比较慢的查询来说,这是最重要的诊断工具之一。通过查看一个查询的explain()输出信息,可以知道查询使用了哪个索引,以及是如何使用的。对于任意查询,都可以在最后添加一个explain()调用(与调用sort()或者limit()一样,不过explain()必须放在最后)。
最常见的explain()输出有两种类型:使用索引的查询和没有使用索引的查询。对于特殊类型的索引,生成的查询计划可能会有些许不同,但是大部分字段都是相以的。另外,分片返回的是多个explain()的聚合,因为查询会在
多个服务器上执行。不使用索引的查询的exlpain()是最基本的explain()类型。如果一个查询不使用索引,是因为它使用了"BasicCursor"(基本游标)。反过来说,大部分使用索引的查询使用的是BtreeCursor(某些特殊类型的索引,比如地理空间索引,使用的是它们自己类型的游标)。
对于使用了复合索引的查询,最简单的情况下的explain()如下:
db.users.find({"age": 42}).explain()
{ explainVersion: '1',
queryPlanner:
{ namespace: 'test.users',
indexFilterSet: false,
parsedQuery: { age: { '$eq': 42 } },
maxIndexedOrSolutionsReached: false,
maxIndexedAndSolutionsReached: false,
maxScansToExplodeReached: false,
winningPlan:
{ stage: 'FETCH',
inputStage:
{ stage: 'IXSCAN',
keyPattern: { age: 1, username: 1 },
indexName: 'age_1_username_1',
isMultiKey: false,
multiKeyPaths: { age: [], username: [] },
isUnique: false,
isSparse: false,
isPartial: false,
indexVersion: 2,
direction: 'forward',
indexBounds: { age: [ '[42, 42]' ], username: [ '[MinKey, MaxKey]' ] } } },
rejectedPlans: [] },
command: { find: 'users', filter: { age: 42 }, '$db': 'test' },
serverInfo:
{ host: 'zhangchenglongdeMacBook-Pro.local',
port: 27017,
version: '5.0.17',
gitVersion: '197466e20bef76222c1ad85204633163beba3009' },
serverParameters:
{ internalQueryFacetBufferSizeBytes: 104857600,
internalQueryFacetMaxOutputDocSizeBytes: 104857600,
internalLookupStageIntermediateDocumentMaxSizeBytes: 104857600,
internalDocumentSourceGroupMaxMemoryBytes: 104857600,
internalQueryMaxBlockingSortMemoryUsageBytes: 104857600,
internalQueryProhibitBlockingMergeOnMongoS: 0,
internalQueryMaxAddToSetBytes: 104857600,
internalDocumentSourceSetWindowFieldsMaxMemoryBytes: 104857600 },
ok: 1 }
基本用法
db.collection.find({}).explain();
db.collection.explain().aggregate([]);
explain有三种模式:
- queryPlanner(默认):使用queryPlanner只列出所有可能执行的方案,不会执行实际的语句,显示已经胜出的方案winningPlan。
- executionStats:使用executionStats只执行winningPlan方案,并输出结果。
- allPlansExecution:使用allPlansExecution执行所有的方案,并输出结果。
不用模式的用法:
db.collection.find({}).explain('executionStats');
db.collection.find({}).explain('allPlansExecution');
explain内容解读
queryPlanner内容:
queryPlanner:Object
namespace:"test.users"
indexFilterSet:false
parsedQuery:Object
age:Object
$eq:42
maxIndexedOrSolutionsReached:false
maxIndexedAndSolutionsReached:false
maxScansToExplodeReached:false
winningPlan:Object
stage:"FETCH"
inputStage:Object
stage:"IXSCAN"
keyPattern:Object
age:1
username:1
indexName:"age_1_username_1"
isMultiKey:false
multiKeyPaths:Object
age:Array
username:Array
isUnique:false
isSparse:false
isPartial:false
indexVersion:2
direction:"forward"
indexBounds:Object
age:Array
0:"[42, 42]"
username:Array
0:"[MinKey, MaxKey]"
rejectedPlans:Array
stage阶段类型如下:
- COLLSCAN:全表扫描
- IXSCAN:索引扫描
- FETCH:根据索引去检索指定document
- SHARD_MERGE:将各个分片返回数据进行merge
- SORT:表明在内存中进行了排序
- LIMIT:使用limit限制返回数
- SKIP:使用skip进行跳过
- IDHACK:针对_id进行查询
- SHARDING_FILTER:通过mongos对分片数据进行查询
- COUNT:利用db.coll.explain().count()之类进行count运算
- COUNTSCAN: count不使用Index进行count时的stage返回
- COUNT_SCAN: count使用了Index进行count时的stage返回
- SUBPLA:未使用到索引的$or查询的stage返回
- TEXT:使用全文索引进行查询时候的stage返回
- PROJECTION:限定返回字段时候stage的返回
executionStats内容解读
executionStats:Object
executionSuccess:true
nReturned:1
executionTimeMillis:0
totalKeysExamined:1
totalDocsExamined:1
executionStages:Object
stage:"FETCH"
nReturned:1
executionTimeMillisEstimate:0
works:2
advanced:1
needTime:0
needYield:0
saveState:0
restoreState:0
isEOF:1
docsExamined:1
alreadyHasObj:0
inputStage:Object
stage:"IXSCAN"
nReturned:1
executionTimeMillisEstimate:0
works:2
advanced:1
needTime:0
needYield:0
saveState:0
restoreState:0
isEOF:1
keyPattern:Object
age:1
username:1
indexName:"age_1_username_1"
isMultiKey:false
multiKeyPaths:Object
age:Array
username:Array
isUnique:false
isSparse:false
isPartial:false
indexVersion:2
direction:"forward"
indexBounds:Object
age:Array
0:"[42, 42]"
username:Array
0:"[MinKey, MaxKey]"
keysExamined:1
seeks:1
dupsTested:0
dupsDropped:0
allPlansExecution:Array
hint()
如果发现MongoDB使用的索引与自己希望它使用的索引不一致,可以使用hint()强制MongoDB使用特定的索引。例如,如果希望MongoDB在上个例子的查询中使用{"username":1,"age":1}
索引,可以这么做:
db.c.find({"age":14,"username":/.*/}).hint({"username"1,"age"1})
如果查询没有使用你希望它使用的索引,于是你使用hint强制MongoDB使用某个索引,那么应该在应用程序部署之前在所指定的索引上执行explain()。如果强制MongoDB在某个查询上使用索引,而这个查询不知道如何使用这个索引,这样会导致查询效率降低,还不如不使用索引来得快。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)