1.MySql基础架构之SQL语句的执行

news/2025/1/19 16:29:47/文章来源:https://www.cnblogs.com/qiwenforever/p/18679676

1.MySQL数据库的整体架构

image-20250119102426368

(i)连接器:连接器负责与客户端建立连接,获取权限、维持和管理连接。连接命令中的mysql是客户端工具,用来建立服务端连接。在完成经典的TCP握手后,连接器就要开始认证你的身份,这个时候用的就是你输入的用户名和密码。

​ 如果用户名密码认证通过,连接器会到权限表里面查出你拥有的权限。之后,这个连接里面的权限判断逻辑,都将依赖于此时读到的权限。这就意味着,一个用户成功建立连接后,即使你用管理员账号对这个用户的权限做了修改,也不会影响已经存在连接的权限。修改完成后,只有再新建的连接才会使用新的权限设置。

​ 连接完成后,如果你没有后续的动作,这个连接就处于空闲状态,你可以在 showprocesslist 命令中看到它。文本中这个图是 show processlist 的结果,其中的Command 列显示为“Sleep”的这一行,就表示现在系统里面有一个空闲连接。客户端如果太长时间没动静,连接器就会自动将它断开。这个时间是由参数 wait_timeout控制的,默认值是 8 小时。

MySql连接数量的限制

MySQL服务支持的最大连接时由max_connection参数控制的,超过这个数值系统就会拒绝接下来的所有请求,并报错"Too many connections"

MySql长短连接问题

MySQL也和Http一样,有短连接和长连接

短连接概念:

连接mysql服务(TCP三次握手)

执行sql

断开mysql服务(TCP四次挥手 )

长连接概念:

连接mysql服务(TCP三次握手)

执行sql

执行sql

执行sql

...

断开mysql服务(TCP四次挥手)

长连接占用内存过多的问题怎么解决

①定期断开长连接。使用一段时间,或者程序里面判断执行过一个占用内存的大查询后,断开连接,之后要查询再重连。

②如果你用的是 MySQL 5.7 或更新版本,可以在每次执行一个比较大的操作后,通过执行mysql_reset_connection 来重新初始化连接资源。这个过程不需要重连和重新做权限验但是会将连接恢复到刚刚创建完时的状态。

连接器内容总结

  • 与客户端进行TCP三次握手连接
  • 校验客户端用户名和密码,如果用户名和密码不对,就会报错
  • 如果用户名和密码都对了,会读取该用户的权限,然后后面的逻辑判断都会基于此权限

2.查询缓存

​ 连接建立完成后,你就可以执行 select 语句了。执行逻辑就会来到第二步:查询缓存。MySQL 拿到一个查询请求后,会先到查询缓存看看,之前是不是执行过这条语句。行过的语句及其结果可能会以 key-value 对的形式,被直接缓存在内存中。key 是查询的语句,value 是查询的结果。如果你的查询能够直接在这个缓存中找到 key,那么这个value 就会被直接返回给客户端。

​ 如果语句不在查询缓存中,就会继续后面的执行阶段。执行完成后,执行结果会被存入查询缓存中。你可以看到,如果查询命中缓存,MySQL 不需要执行后面的复杂操作,就可以直接返回结果,这个效率会很高。

但是大部分时候,不建议使用缓存。大多时候查询缓存弊大于利

查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会被清空。因此很可能你费劲地把结果存起来,还没使用呢,就被一个更新全清空了。对于更新压力大的数据库来说,查询缓存的命中率会非常低。除非你的业务就是有一张静态表,很长时间才会更新一次。比如,一个系统配置表,那这张表上的查询才适合使用查询缓存。

需要注意的是,MySQL 8.0 版本直接将查询缓存的整块功能删掉了,也就是说 8.0 开始彻底没有这个功能了。

3.解析器

(i)词法分析,MySQL会根据你输入的字符串识别出关键字出来

(ii)语法分析,会根据词法分析的结果,语法分析器会根据语法规则,判断你输入的这个SQL语句是否满足MySQL语法,如果没有问题就会构建SQL语法树,这样方便后面的模块获取SQL类型、表名,字段名,where条件

4.执行SQL

经过解析器后,就要进行执行SQL查询语句的流程了,每条SELECT查询语句可以分为以下三个阶段

  • prepare阶段,也就是预处理阶段
  • optimize阶段,也就是优化阶段
  • execute阶段,也就是执行阶段

①预处理阶段

  • 检查SQL查询语句中的表或者字段是否存在
  • select *中的*,扩展到所有列

②优化器阶段

优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序。比如你执行下面这样的语句,这个语句是执行两个表的 join:

mysql> select * from t1 join t2 using(ID) where t1.c=10 and t2.d=20;

既可以先从表 t1 里面取出 c=10 的记录的 ID 值,再根据 ID 值关联到表 t2,再判断 t2里面 d 的值是否等于 20。

也可以先从表 t2 里面取出 d=20 的记录的 ID 值,再根据 ID 值关联到 t1,再判断 t1 里面 c 的值是否等于 10。

这两种执行方法的逻辑结果是一样的,但是执行的效率会有不同,而优化器的作用就是决定选择使用哪一个方案。

③执行器阶段

经历完优化器后,就确定了执行方案,接下来MySQL就真的开始执行语句,这个工作是由执行器完成的。在执行的过程中,执行器就会和存储引擎交互了,交互是以记录为单位的。还会判断一下用户是否对该表有操作权限

执行器和存储引擎交互有三种执行过程

  • 主键索引查询
  • 全表扫描
  • 索引下推

主键索引查询

以本文开头查询语句为例,看看执行器是怎么工作的

select * from product where id=1

这条记录语句的查询条件用到了主键索引,而且是等值查询,同时主键id唯一,不会有id不唯一的记录,索引优化器决定用访问类型const进行查询,也就是使用主键索引查询一条记录,那么执行器与存储引擎的执行流程是这样的:

  • 执行器第一次查询,会调用read_first_record函数指针指向的函数,因为优化器选择的访问类型为const,这个函数被指向InnoDB引擎索引查询的接口,把条件id=1交给存储引擎,让存储引擎定位一条符合条件的第一条记录
  • 存储引擎通过主键索引的B+数结构定位到id=1的第一条记录,如果记录不存在的,就会向执行器上报记录找不到错误,然后查询结束。如果记录是存在的,就会将记录返回给执行器
  • 执行器从存储引擎读到记录之后,接着判断记录是否符合查询条件,如果符合则发送给客户端,如果不符合则跳过该记录
  • 执行器查询的过程是一个while循环,所以还会再查一次,但是由于不是第一次查询所以会调用read_record函数指针指向函数,因为优化器选择的访问类型为const,这个函数指针被指向了一个永远返回-1的函数,所以当调用该函数的时候,执行器就退出循环,也就结束查询了。

全表扫描

eg:select * from product where name='phone'

这条查询语句的查询条件没有用到索引,所以优化器决定选用访问类型为ALL进行查询,也就是全表扫描这种方式查询,那么这时执行器与存储引擎的执行流程是这样的:

  • 执行器第一次查询,会调用read_first_record函数指针指向的函数,因为优化器选择的访问类型为ALL,这个函数指针被指向InnoDB引擎全扫描接口,让存储引擎读取表中的第一条记录;
  • 执行器会判断读到的这条记录的name是不是iphone,如果不是则跳过;如果是则将记录发给客户(Server层每从存储引擎读到一条记录就会发送给客户端,之所以客户端显示的是所有记录,是因为客户端在查询完成之后才会显示)
  • 执行器查询的过程是一个while循环,所以还会再查一次,会调用read_record函数指针指向的函数,因为优化器选择的访问类型为all,read_record函数指针指向的还是InnoDB引擎扫描的接口,所以接着向存储引擎层要求继续读刚刚读到的那条记录的下一条记录,存储记录把下一条记录取出后就将其返回给执行器(Server层),执行器继续判断条件,不符合查询条件的即跳过该记录,否则发送到客户端
  • 一直重复上述过程,直到存储引擎把表中的记录全部读完,然后向执行器(Server层)返回了读取完毕的信息
  • 执行器收到存储引擎报告的查询完毕的信息,退出循环,停止查询

索引下推

索引下推能够减少二级索引在查询时的回表操作,提高查询效率,因为它将Server层负责的事情交给了存储引擎去处理了

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

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

相关文章

ATF引导启动流程整理-Part2:BL1引导启动流程整理

接上一章的介绍,本文详细整理一下 BL1 阶段的流程 Ch3: ATF启动流程 上面一章简单的介绍了 ATF的隔离和划分,下面就介绍一下使用 ATF 初始启动的流程。ARM v8的启动流程包含多个阶段,典型的官方定义的标志阶段包括 BL1、BL2、BL31、BL32、BL33,根据不同需求这些阶段可以添加…

推荐一款非常好用的在线 SSH 管理工具

前言 SSH工具在远程连接、文件传输、远程管理和增强安全性等方面发挥着重要作用,是我们开发人员和系统管理员不可或缺的工具。今天大姚给大家推荐一款非常好用的在线 SSH 管理工具:Xterminal。工具介绍 Xterminal一个好用的在线SSH、SFTP工具,支持跨平台(Windows、Linux、M…

代码随想录——动态规划背包问题总结

https://www.programmercarl.com/背包总结篇.html#听说背包问题很难-这篇总结篇来拯救你了

DASCTF --wp--web

1、Rank-lSsti的报错查询cycler没用被禁用,很常规的到达popen阶段{{cycler.__init__.__globals__.__builtins__[__import__](os).popen(ls).read()}}正常在浏览器中无法查看,使用pythonimport requestswith requests.Session() as session: url_phone = http://139.155.12…

动态规划——26单词拆分

这道题用代码随想录的解释有点牵强,第二层for循环和递推公式也没有说明白。代码 class Solution { public:bool wordBreak(string s, vector<string>& wordDict) {unordered_set<string> set(wordDict.begin(),wordDict.end());//字典单词是物品,s是背包int …

使用Wireshark抓包工具

下载Wireshark: https://www.wireshark.org/ 选择要监听的网卡 用户界面数据包分层结构关于过滤器 分为 显示过滤器 和 捕获过滤器 显示过滤器:过滤已捕获的数据包,符合条件的进行显示 ip.addr == ip地址 # 过滤所有与该网站相关的数据包ip.addr == ip地址 && http …

【NodeJS渗透】提取和分析.asar文件的案例研究

免责声明 ⽂中所涉及的技术、思路和⼯具仅供以安全为⽬的的学习交流使⽤,任何⼈不得将其⽤于⾮法⽤途以及盈利等⽬的,否则后果⾃⾏承担。所有渗透都需获取授权!硬编码密钥(在SQLite中)和加密算法(在AesFormula.js文件中)信息泄露导致真实凭据被泄露 一、案例研究 本节案…

Spring,Spring Ioc,Bean详解

Spring框架Spring框架是Java应用最广的框架,其的成功来自于理念,并非是技术,其中几个理念非常重要,例如IoC(控制反转),AOP(面向切面编程)Spring的优势低耦合/低侵入(解耦)Spring通过IoC(控制反转)和DI(依赖注入)来实现低耦合高内聚声明式事务管理Spring基于AOP的方式,使其能够在…

远程桌面键盘记录器

针对远程桌面协议 (RDP) 相关进程的击键记录器,它利用键盘输入挂钩,允许其记录某些上下文中的击键(例如在 mstsc.exe 和 CredentialUIBroker.exe 中) 使用vs直接编译就可以了运行TakeMyRDP.exe打开mstsc,输入ip地址,输入账号密码密码直接显示出来,这个exe不需要高权限运行…

【nginx】Nginx重定向方法

Nginx重定向配置是一个功能强大且灵活的工具,可以根据具体需求实现各种重定向规则。 以下是对Nginx请求重定向配置方法的详细解析:1、基本概念 请求重定向是指当客户端向服务器发送一个请求时,服务器根据一定的规则将客户端的请求引导到另外一个URL的过程。在Nginx中,通过r…

利用mybatis拦截器记录sql,辅助我们建立索引(二)

背景 上一篇中讲述了mybatis的mapper初始化过程和执行过程,这篇再讲讲具体的拦截器的使用,以实现记录sql到持久化存储,通过分析这些sql,我们就能更方便地建立索引。 利用mybatis拦截器记录sql,辅助我们建立索引(一) 我本地项目的大概版本: spring boot版本2.7,mybatis版…

JMeter通过JSON提取器获取任意一行数据中的多个字段

存在如下响应信息: { "result": { "data": [ { "字段1": "DK-01", "字段2": null, "字段3": "210(3mm/40kg)",}, {&q…