MongoDB系列之查询计划

概述

一个查询具体如何被执行的过程,称为查询计划。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:是否设置indexFilter,indexFilter可决定查询优化器对于某个查询将如何使用索引
  • serverInfo:MongoDB服务器概要信息
  • 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将各个分片的返回结果进行merge
SORT在内存中进行排序
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次,numWorks=Math.max(10000, 0.3×collection.count)
  • 返回结果达到numResults个,numResults=Math.min(101, query.getN(), query.getLimit()),其中query.getN()来自getMore命令,query.getLimit()则只有限制limit条件才会出现。这两个参数只有存在时才会参与比较,否则numResults默认就是101。

为每个计划的执行情况打分,计算分数的因子来自下面几点:

  • isEOF是否为true,如果出现isEOE则说明扫描的指针已经到达末尾。如果计划提前结束,则扫描会获得最大的机会。
  • advance/workUnits(%),如果返回的结果数占扫描数的比例越大,则代表扫描效率越高。

是否存在以下低效率的阶段:

  • PROJECTION+FETCH(非覆盖索引查询)
  • 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进阶与实战:微服务整合、性能优化、架构管理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/280460.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows管理多版本nodejs方法

参考:window操作系统安装多个版本的nodejs——nodejs版本控制工具nvm_windows node多版本共存-CSDN博客 前排: 建议把原来电脑装的nodejs卸载干净,再干这个步骤,可以避免出现一些状况;;;另&…

免费PDF转换和编辑工具 PDFgear 2.1.4

PDFgear是一款功能强大的 PDF 阅读及转换软件。 它支持多种文件格式的转换和编辑,同时还提供了丰富的功能模块,如签名、表单填写等,方便用户进行多样化的操作。 该软件界面简洁美观,操作简单易懂,适合不同层次的用户…

【论文阅读】通过组件对齐评估和改进 text-to-SQL 的组合泛化

Measuring and Improving Compositional Generalization in Text-to-SQL via Component Alignment NAACL 2022| CCF B Abstract 在 text-to-SQL 任务中,正如在许多 NLP 中一样,组合泛化是一个重大挑战:神经网络在训练和测试分布不同的情况…

iostream、fstream、sstream、string、vector、unordered_map、stack

iostream 用于输入输出操作&#xff0c;包含了处理标准输入输出流的功能&#xff08;例如&#xff0c;cin, cout, cerr等&#xff09;。 #include <iostream>int main() {int number;std::cout << "Enter a number: ";std::cin >> number;std::…

基于Springboot的防疫物资管理信息系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的防疫物资管理信息系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系…

docker部署grafana graphite stastd实时监控告警配置_亲测成功

docker部署grafana graphite stastd实时监控告警配置_亲测成功 实时监控请求的次数和响应时间及异常报警 项目中需要监控API接口的调用情况,如:调用次数,每次调用耗时,调用高峰期,异常报警等 grafana graphite stastd这一套对代码没有侵入,也不会影响接口性能 安装docker环…

【C语言】【牛客】BC136 KiKi判断上三角矩阵

文章目录 题目 BC136 KiKi判断上三角矩阵思路代码呈现 题目 BC136 KiKi判断上三角矩阵 链接: link 思路 这题很简单但是再牛客中属于中等题 我们通过读题发现 2<n<10 &#xff0c;所以我们首先创建一个变量 n 以及一个 10*10 个元素数组 然后题目是判断该矩阵是否是…

Fetch、Axios 和 jQuery(Ajax) 三种常用的网络请求技术

Fetch、Axios 和 jQuery(Ajax) 是三种常用的网络请求技术&#xff0c;它们各自有着不同的特点和优势。本文将对这三种技术进行详细的介绍和比较&#xff0c;以帮助开发者更好地选择和使用合适的网络请求技术。 一、Fetch Fetch(浏览器自带) 是一种现代的网络请求 API&#xff…

强大的文本编辑器:Sublime Text for Mac注册激活版

Sublime Text for Mac是一款功能强大的文本编辑器&#xff0c;特别适合程序员和开发者使用。它提供了丰富的功能&#xff0c;如智能代码补全、语法高亮、自定义快捷键、项目管理、多行选择、自动保存等&#xff0c;以提高代码编写效率和舒适度。此外&#xff0c;Sublime Text还…

SQLiteC/C++接口详细介绍sqlite3_stmt类(四)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍sqlite3_stmt类&#xff08;三&#xff09; 下一篇&#xff1a;SQLiteC/C接口详细介绍sqlite3_stmt类&#xff08;五&#xff09; 7. sqlite3_bind_parameter_count函数 sqlite3_bind_param…

数据库设计三大范式

第一范式 确保每列保持原子性 即数据库表中的所有字段值都是不可分解的原子值 如果地址这个字段频繁访问&#xff0c; 则将地址这个属性重新划分为 省份 城市&#xff0c;详细地址等部分进行存储&#xff0c;这样才算是满足数据库的第一范式 第二范式 确保表中的每列都和主…

SpringCloud中的@EnableDiscoceryClient和@EnableFeignClients注解的作用解析、RPC远程过程调用

目录 EnableDiscoveryClient 服务发现的核心概念 服务注册中心 EnableDiscoveryClient注解的作用 服务心跳健康检查 使用示例 EnableFeignClients Feign简介 EnableFeignClients注解的作用 RPC&#xff08;Remote Procedure Call&#xff09; 参考链接 Spring Cloud…

企业工商年报注册注销商标注册异常处理小程序开源版开发

企业工商年报注册注销商标注册异常处理小程序开源版开发 1、独立业务模型包括&#xff1a;企业工商年报、企业工商登记注册、企业注销登记、企业异常处理。 2、通用业务模型适合各种业务&#xff0c;比如&#xff1a;商标注册代理、财务会计服务、企业版权登记登。 当然&…

CAPL如何实现TCP Packet的option字段

在TCP协议中,主机可以根据自身的需要决定TCP通信时是否携带option字段,来扩展TCP功能。option字段属于TCP首部的扩展部分,且是可选项,TCP根据首部中的offset字段值确定TCP报文是否携带option字段。 TCP首部固定的部分有20个字节,如果没有扩展部分(option字段),20个字节…

《论文阅读》带边界调整的联合约束学习用于情感原因对提取 ACL 2023

《论文阅读》带边界调整的联合约束学习用于情感原因对提取 前言简介Clause EncoderJoint Constrained LearningBoundary Adjusting损失函数前言 亲身阅读感受分享,细节画图解释,再也不用担心看不懂论文啦~ 无抄袭,无复制,纯手工敲击键盘~ 今天为大家带来的是《Joint Cons…

图像分割论文阅读:Adaptive Context Selection for Polyp Segmentation

这篇论文的主要内容是关于一种用于息肉分割的自适应上下文选择网络&#xff08;Adaptive Context Selection Network&#xff0c;简称ACSNet&#xff09; 1&#xff0c;模型的整体结构 模型的整体结构基于编码器-解码器框架&#xff0c;并且包含了三个关键模块&#xff1a;局部…

spring boot学习第十四篇:使用AOP编程

一、基本介绍 1&#xff0c;什么是 AOP &#xff08;1&#xff09;AOP 为 Aspect Oriented Programming 的缩写&#xff0c;意为&#xff1a;面向切面编程&#xff0c;通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。 &#xff08;2&#xff09;利用 AOP…

如何实现跨标签页通讯

什么是跨标签页通讯 同一浏览器&#xff0c;可以打开多个标签页&#xff0c;跨标签页通讯就是&#xff0c;一个标签页能够发消息给另一标签页。 有哪些实现方案 localStorage &#xff08;window.onstorage事件监听&#xff09;BroadcastChannel&#xff08;广播&#xff09…

opengl日记10-opengl使用多个纹理示例

文章目录 环境代码CMakeLists.txt文件内容不变。fragmentShaderSource.fsvertexShaderSource.vsmain.cpp 总结 环境 系统&#xff1a;ubuntu20.04opengl版本&#xff1a;4.6glfw版本&#xff1a;3.3glad版本&#xff1a;4.6cmake版本&#xff1a;3.16.3gcc版本&#xff1a;10.…

图片编辑器中实现文件上传的三种方式和二进制流及文件头校验文件类型

背景 最近在 vue-design-editor 开源项目中实现 psd 等多种文件格式上传解析成模板过程中, 发现搞定设计文件上传没有使用 input 实现文件上传, 所以我研究了一下相关技术, 总结了以下三种文件上传方法 input 文件选择window.showOpenFilePicker 和 window.showDirectoryPicke…