eclipse tomcat 网站开发,北京企业网站建设费用,托管管理系统app,wordpress资源站主题概述
一个查询具体如何被执行的过程#xff0c;称为查询计划。MongoDB采用自底向上的方式来构造查询计划#xff0c;每一个查询计划#xff08;query plan#xff09;都会被分解为若干个有层次的阶段#xff08;stage#xff09;。整个查询计划最终会呈现出一颗多叉树。…概述
一个查询具体如何被执行的过程称为查询计划。MongoDB采用自底向上的方式来构造查询计划每一个查询计划query plan都会被分解为若干个有层次的阶段stage。整个查询计划最终会呈现出一颗多叉树。 整个计算过程是从下向上投递的每一个阶段的计算结果都是其上层阶段的输入每一个阶段都有自己的逻辑语义。
执行模式
explain有3种执行模式
queryPlanner默认仅进行查询计划分析输出计划中的阶段信息。executionStats执行模式在查询计划分析后将按照winningPlan执行查询并统计过程信息。allPlansExecution全计划执行模式将执行所有计划包括winningPlan和rejectPlans并返回全部的过程统计信息。
根据MongoDB版本不同explain命令的输出结果包含不同的丰富的信息字段。以MongoDB 6.0.5版本为例执行命令db.game.find().explain();或db.game.find().explain(queryPlanner);输出完全一样
[{command: {find: game,filter: {},$db: test},explainVersion: 1,ok: 1,queryPlanner: {namespace: test.game,indexFilterSet: false,parsedQuery: {},queryHash: 17830885,planCacheKey: 17830885,maxIndexedOrSolutionsReached: false,maxIndexedAndSolutionsReached: false,maxScansToExplodeReached: false,winningPlan: {stage: COLLSCAN,direction: forward},rejectedPlans: []},serverInfo: {host: johnnydeMBP.ada.local,port: 27017,version: 6.0.5,gitVersion: c9a99c120371d4d4c52cbb15dac34a36ce8d3b1d},serverParameters: {internalQueryFacetBufferSizeBytes: 104857600,internalQueryFacetMaxOutputDocSizeBytes: 104857600,internalLookupStageIntermediateDocumentMaxSizeBytes: 104857600,internalDocumentSourceGroupMaxMemoryBytes: 104857600,internalQueryMaxBlockingSortMemoryUsageBytes: 104857600,internalQueryProhibitBlockingMergeOnMongoS: 0,internalQueryMaxAddToSetBytes: 104857600,internalDocumentSourceSetWindowFieldsMaxMemoryBytes: 104857600}}
]部分字段解读
queryPlanner描述查询计划queryPlanner.indexFilterSet是否设置indexFilterindexFilter可决定查询优化器对于某个查询将如何使用索引serverInfoMongoDB服务器概要信息serverParameters参数设置
执行命令db.game.find().explain(executionStats);输出内容除executionStats字段外和db.game.find().explain(queryPlanner);完全一致都出部分
executionStats: {executionSuccess: true,nReturned: 0,executionTimeMillis: 0,totalKeysExamined: 0,totalDocsExamined: 0,executionStages: {stage: COLLSCAN,nReturned: 0,executionTimeMillisEstimate: 0,works: 2,advanced: 0,needTime: 1,needYield: 0,saveState: 0,restoreState: 0,isEOF: 1,direction: forward,docsExamined: 0}
}executionStats执行过程统计捕获计划在执行过程中的相关信息只有在executionStats或allPlansExecution模式下才会输出。
执行命令db.game.find().explain(allPlansExecution);相比于db.game.find().explain(executionStats);输出结果多一个allPlansExecution字段。
IndexFilter
queryPlanner.winningPlan.stage
queryPlanner.winningPlan.stage参数如下
类型描述COLLSCAN全表扫描IXSCAN索引扫描FETCH根据索引检索指定的文档SHARD_MERGE将各个分片的返回结果进行mergeSORT在内存中进行排序LIMIT使用limit限制返回结果数量SKIP使用skip进行跳过IDHACK针对_id字段进行查询SHANRDING_FILTER通过mongos对分片数据进行查询COUNT利用db.coll.explain().count()进行count运算COUNTSCAN不使用index进行count时COUNT_SCAN使用Index进行count时SUBPLA未使用到索引的$or查询的stage返回TEXT使用全文索引进行查询时候的stage返回PROJECTION限定返回字段时候stage的返回
缓存
一个查询操作可能对应多个不同的查询计划。无论是哪一种方式都会先经过内部的评分机制进行评估最终选出一个最优的执行方案。查询计划的评估必然会产生一定的计算开销。
MongoDB提供PlanCache用以实现查询计划缓存能力可避免在一定条件内对同一个查询模型进行重复性的分析和评估工作。如果对于某个查询已经有了确定性的选择查询优化器会直接做出选择此时缓存并不会启用。 步骤解读
查询开始执行判断PlanCache中是否有对应的缓存。如果没有缓存则进入计划生成阶段执行如下步骤 分析查询语句与全部索引产生候选计划。评估查询计划包括对计划的并发执行、采样。选择最优的计划。将计划存入缓存。 如果存在缓存则触发replanning机制评估查询性能此时有两种结果 查询性能不达标淘汰缓存重新生成计划。查询性能达标采纳计划。 执行最终计划返回结果。
查询模型query shape是对于当前查询场景的唯一性结构描述。查询优化器会首先将查询请求解析为某个查询模型根据这个模型再进行计划缓存的查询。查询模型的组成包括以下3个部分
query描述查询条件的结构该结构由条件的字段、操作符谓词以及条件的嵌套关系组成并不包含查询条件的具体值projection描述即将返回哪些字段sort描述排序的规则。
如果同时存在多个候选计划那么需要根据一种评分机制从这些计划中选出一个最优计划这就涉及计划的评优evaluate过程。
首先让所有计划都同时执行一定量的扫描任务扫描任务在满足以下条件时停止
扫描次数达到numWorks次numWorksMath.max(10000, 0.3×collection.count)返回结果达到numResults个numResultsMath.min(101, query.getN(), query.getLimit())其中query.getN()来自getMore命令query.getLimit()则只有限制limit条件才会出现。这两个参数只有存在时才会参与比较否则numResults默认就是101。
为每个计划的执行情况打分计算分数的因子来自下面几点
isEOF是否为true如果出现isEOE则说明扫描的指针已经到达末尾。如果计划提前结束则扫描会获得最大的机会。advance/workUnits(%)如果返回的结果数占扫描数的比例越大则代表扫描效率越高。
是否存在以下低效率的阶段
PROJECTIONFETCH非覆盖索引查询SORT内存排序AND_HASH|STAGE_AND_SORTED索引正交阶段。
任意一种低效阶段的存在都会导致候选计划被扣分。
最后根据所得分数进行排序得分最高的计划被评选为最优计划并写入缓存。
对于已经缓存的计划MongoDB仍会采用一种replaining的机制来保证其高效性。在返回缓存的计划之前首先对该计划进行扫描采样这次的采样数相比之前的numWorks会扩大10倍
扫描过程中如果返回numResults个条目或者到达EOF则达到通过pass条件此时仍然选用此计划。如果超过采样数之后仍未达到通过条件则转为失败fail状态触发replain过程此时将重新评选计划。如果扫描过程中出错则同样会变成失败状态此时也会触发replain过程。
触发查询计划缓存清除的时机
执行PlanCache.clear方法。创建、删除索引或者执行集合的drop操作。重启MongoDB进程。
强制命中
在某些极少情况下某些查询产生的最终计划可能并不是你想要的。事实上想实现一个完美的查询计划是非常困难的MongoDB在查询优化器上做了很多合理性方面的努力如提供一些干预的手段。
hint方法实现对查询计划机制的干预在查询计划中使用hint语句可以让MongoDB忽略查询优化器的结果从而直接使用指定的索引。hint方法参数可以传入索引的定义对象也可以是索引的名称。
IndexFilter方法也可以于预查询索引
db.runCommand({planCacheSetFilter: test,query: {a: 3, b: 4},index: [{b: 1}]}
)执行planCacheSetFilter命令会在test集合中增加一个IndexFilter对象该对象将会自动关联到同时包含a字段与b字段的等值查询并引导查询优化器使用{b: 1}这个索引。
IndexFilter的优先级高于hint方法如果查询优化器发现关联的IndexFilter则一定会忽略hint语句。但是IndexFilter并不能保证查询优化器最终一定会选择对应的索引事实上优化器会将这些索引与全表扫描方式一并进行评估再抉择出最终的结果。在最坏的情况下如果指定不存在的索引就会导致全表扫描。
IndexFilter是内存态的重启MongoDB则会自动失效。另外也可以使用planCacheClearFilters进行擦除。
参考
MongoDB进阶与实战微服务整合、性能优化、架构管理