这篇主要讲解的是 MongoDB explain
指令的 executionStats
项目。
使用此模式进行 explain,会根据你输入的语法,在 query optimizer 找出最佳的查询计画,并且 实际执行你的语法,无论是查询或者新增删除修改。但是请不用担心,这样做并不会真的去改变任何资料库内容,只是协助、更贴近真实情况下,你的语法执行结果如何。
查询语法在 explain 参数中带入 executionStats
,即可。
db.collection.find().explain("executionStats")
马上进入重头戏,实际执行的部分。我们沿用了上一篇文章的范例,一样是查询 name
栏位,参数则指令了executionStats。
db.collection.find("name":"Devil").explain("executionStats")
queryPlanner
、serverInfo
"executionStats" : {
"executionSuccess" : true, // 执行结果
"nReturned" : 1, // 回传了几个文件
"executionTimeMillis" : 0, // 执行时间
"totalKeysExamined" : 1, // 总共扫瞄了几把 key (代表有走在 index 上)
"totalDocsExamined" : 1, // 总共检查了几个档案
"executionStages" : { // 执行阶段
"stage" : "FETCH", // 执行此语法使用的方式,使用 index 查询档案
"nReturned" : 1, // 回传了几个档案
"executionTimeMillisEstimate" : 0,
"works" : 2,
"advanced" : 1,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 1, // 扫描了几个档案
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN", // 在执行阶段,先使用了什麽方式查找,这边是使用 index
"nReturned" : 1,
"executionTimeMillisEstimate" : 0,
"works" : 2,
"advanced" : 1,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"name" : 1.0
},
"indexName" : "name_1", // 使用的 index 名称
"isMultiKey" : false, // 是否为 multi key,如果是在 array 上建立 index,会是 true
"multiKeyPaths" : {
"name" : []
},
"isUnique" : false, // index 属性,这三个可以回头查看我之前 index 文章
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward", // 排序方向,顺向。如果有 sort -1,就会是 backward
"indexBounds" : {
"name" : [
"[\"Devil\", \"Devil\"]"
]
},
"keysExamined" : 1,
"seeks" : 1,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
}
比较简单的部分就直接在范例後面注解了。
首先我们看一下这个结构
"executionStats":{
"executionStages":{
"inputStage":{
"stage" : "IXSCAN"
...
}
}
}
winningPlan 是一个树状的结构,实际上会根据你的查询语法而有一个或多个 inputStage
,所以你可以看到 inputStages
会变成是复数型态。
例如我们今天分别提 age
, name
两个栏位分别新增各一把 index,再使用 or
语法来查询
db.employee.createIndex( { name: 1 } )
db.employee.createIndex( { age: 1 } )
db.employee.find({$or: [{"age":35} ,{"name":"Devil"}] }).explain("executionStats")
就会出现两个 inputStage,如下:
"winningPlan" : {
"stage" : "SUBPLAN",
"inputStage" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "OR",
"inputStages" : [
{
"stage" : "IXSCAN",
"keyPattern" : {
"name" : 1.0
},
"indexName" : "name_1",
},
{
"stage" : "IXSCAN",
"keyPattern" : {
"age" : 1.0
},
"indexName" : "age_1",
}
]
}
}
}
executionStats 格式也是一样的,但因为内容更多,所以这边是先贴 winningPlan 结果。
那如果今天我只有一把 key,但还是用 or 来查询两个栏位,那会变成什麽结果呢?
答案是 1 个 inputStage,因为已经是 COLLSCAN 罗~
官网特别提到的项目,关於 $or
与 $in
运算子,官方直接告诉你要使用$in
。
假设你要查询 name 栏位是 "Ada" 或 "Bob",不要使用
{$or: [{"name":"Ada"}, {"name":"Bob"}]}
{"name":{$in:["Ada", "Bob"]}}
个人补充:依我的经验,因为看到官方提到这个案例,於是在猜想否定类型的运算子是不是也有相同效能问题,後来经过测试,确实是效能比较差,例如 $nin
这种。(当时是 3 版左右吧,不确定现在怎麽样 5.0.1 了...)
works : 2
这个 works
就连官方文件都着墨得少。 works 可分为多个工作单元 work unit
,像是查询 single field index key,或是依照 key 读取回一个文件,或是针对取回文件进行 project
都算是一个工作单元,基本上就是最小工作单位的意思。假设一个好的查询,通常会是 nReturned 的数量 +1,为什麽呢? nReturned 就是你查询返回的文件数量,+1 则代表是查询 index 这件工作,因此整体就是 works = nReturned+1。
isEOF : 1,
执行阶段是否已经读取到结尾的地方。
0
代表尚未1
代表是0
呢?通常是查询语法中带有 limt
的语法,使得该次查询并不会查到结尾。其实还是有很多栏位是我不太理解的,也许之後有翻到文件会再记录下来。至於没写到的,就应该是连相关文献都找不到了XD
{field_a:1, field_b:'b01'},
{field_a:1, field_b:'b012'},
{field_a:2, field_b:'b02'},
{field_a:2, field_b:'b022'},
{field_a:2, field_b:'b023'},
{field_a:3, field_b:'b03'}
我们替 field_a
建立索引,假设查询是 {field_a:2}
,那没什麽问题。
那如果我们查询的是 {field_a:2, field_b:'b023'}
,那麽 MongoDB 就必须要找遍 3 个文件才能找到正确的文件。
从上面的例子能理解独特性的重要,至於要怎麽解这个问题,使用 compound index
就能处理。
status = 'ERROR'
的状态资料是我们关注的,时常需要去看,这个情境就很适合 partial index本系列文章会同步发表於我个人的部落格 Pie Note
>>: Day02 - React component 初认识
今天把昨天写的选取器跟显示东西做串接 首先先写一个json,若会用firebase或App Scri...
大家好~ 我是五岁~ 今天来画四足战车的草图细节~ 首先来画上半部 依照昨天的外型草稿,进一步认真的...
四开四个主题实在太累,JavaScript技术手册阅读笔记这个主题就是读这本书买很久的书,顺便把之前...
延续上篇的table介绍,原本功能都要自己写,那有没有工具可以直接套用呢?有的!那就是神器Data...
自动更新每日个股日成交资讯 结合前几篇所学,我们来做一个可以自动更新日成交资讯的程序吧! Reque...