MySQL执行流程

MySQL执行流程

在使用MySQL时,你是否有疑惑,当我们提交一条SQL给MySQL时它到底是如何执行的?

通过了解MySQL的执行流程一定能解开你的疑惑🤔

MySQL执行流程

总体流程

  1. 客户端通过连接器连接MySQL
  2. 查询执行缓存
  3. 解析器解析SQL
  4. 执行器执行SQL
  5. 调用存储引擎API

⚠️:MySQL8.0之后就把查询执行缓存这一步骤去掉了,效率太低

MySQL架构分为两层:Server层和存储引擎层

在这里插入图片描述

  • Server层负责建立连接、查询缓存、解析SQL、执行SQL。MySQL大部分的核心功能都在这实现。另外,所有的内置函数(如日期、时间、数学和加密函数等)和所有跨存储引擎的功能(如存储过程、触发器、视图等)
  • 存储引擎负责数据的存储和提取。支持InnoDB、MyISAM、Memory等多个存储引擎,不同存储引擎公用一个Server层。从MySQL5.5版本开始,InnoDB成为了MySQL的默认存储引擎。我们常说的索引数据结构,就是又存储引擎层实现的,不同的存储引擎支持的索引类型也不同,比如InnoDB支持的索引类型是B+树

1.连接器

正常请求下,连接数据库我们会使用如下命令

#连接本机MySQL
mysql -u 用户名 -p
# 连接远程MySQL
mysql -h ip地址 -u 用户名 -p

连接的过程会使用到TCP的三次握手🤝,MySQL的底层就是基于TCP协议进行通信的,如果MySQL服务正常运行的话会对你输入的用户名和密码进行验证,如果不存在当前用户或者当前用户不存在对应的权限就会报错(Access denied权限拒绝)

img

如果验证通过,连接器会保存当前用户的权限,在之后的操作中会基于当前这个用户的权限进行判断

查看MySQL当前的客户端连接

show processlist

在这里插入图片描述

MySQL的连接数有限制吗?

查看最大连接数

show variables like 'max_connections';

在这里插入图片描述

可以看到MySQL默认的最大连接数为151,当超过151个客户端同时连接MySQL时,接下来的连接请求就会被拒绝,并报错“Too many connections”

MySQL的连接

MySQL的连接也与Http的连接类似有长连接和短连接之分

// 短连接
连接(三次握手)
执行sql
断开连接(四次挥手)// 长连接
连接(三次握手)
执行sql
执行sql
执行sql
...
断开连接(四次挥手)

使用长连接的好处就是可以减少建立连接和断开连接的过程,所以一般推荐使用长连接

但是,使用长连接后可能会占用内存增多,因为 MySQL 在执行查询过程中临时使用内存管理连接对象,这些连接对象资源只有在连接断开时才会释放。如果长连接累计很多,将导致 MySQL 服务占用内存太大,有可能会被系统强制杀掉,这样会发生 MySQL 服务异常重启的现象。

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

有两种解决方式。

第一种,定期断开长连接。既然断开连接后就会释放连接占用的内存资源,那么我们可以定期断开长连接。

第二种,客户端主动重置连接。MySQL 5.7 版本实现了 mysql_reset_connection() 函数的接口,注意这是接口函数不是命令,那么当客户端执行了一个很大的操作后,在代码里调用 mysql_reset_connection 函数来重置连接,达到释放内存的效果。这个过程不需要重连和重新做权限验证,但是会将连接恢复到刚刚创建完时的状态。

至此,连接器的工作做完了,简单总结一下

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

2.查询缓存

连接器的工作完成后,客户端就可以向MySQL服务发送SQL语句了,MySQL就收到SQL语句后,如果发现是Select查询语句,会去Cache缓存中看看是否有对应的缓存,比如现在我发送给MySQLselect * from t_user语句,如果MySQL发现缓存中存在

缓存:<select * from t_user, 缓存数据>

命中缓存之后,会直接把缓存返回给客户端

但是查询缓存有个很大的缺点(命中率低、占用内存)

对于更新比较频繁的表,查询缓存的命中率很低的,因为只要一个表有更新操作,那么这个表的查询缓存就会被清空。如果刚缓存了一个查询结果很大的数据,还没被使用的时候,刚好这个表有更新操作,查询缓冲就被清空了,相当于缓存了个寂寞。

所以,MySQL 8.0 版本直接将查询缓存删掉了,也就是说 MySQL 8.0 开始,执行一条 SQL 查询语句,不会再走到查询缓存这个阶段了。

对于 MySQL 8.0 之前的版本,如果想关闭查询缓存,我们可以通过将参数 query_cache_type 设置成 DEMAND。

3.解析SQL

解析器会做如下两件事情。

第一件事情,词法分析。MySQL 会根据你输入的字符串识别出关键字出来,例如,SQL语句 select username from userinfo,在分析之后,会得到4个Token,其中有2个Keyword,分别为select和from:

关键字非关键字关键字非关键字
selectusernamefromuserinfo

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

在这里插入图片描述

如果我们输入的 SQL 语句语法不对,就会在解析器这个阶段报错。比如,我下面这条查询语句,把 from 写成了 form,这时 MySQL 解析器就会给报错。

img

但是注意,表不存在或者字段不存在,并不是在解析器里做的,《MySQL 45 讲》说是在解析器做的,但是经过我和朋友看 MySQL 源码(5.7和8.0)得出结论是解析器只负责检查语法和构建语法树,但是不会去查表或者字段存不存在。

那到底谁来做检测表和字段是否存在的工作呢?别急,接下来就是了。

4.执行SQL

执行SQL分为3小步:

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

预处理器的工作

  • 检查SQL查询语句中的表或者字段是否存在;
  • select *中的*符号,拓展为表上所有的列;

下面这条查询语句,test 这张表是不存在的,这时 MySQL 就会在执行 SQL 查询语句的 prepare 阶段中报错。

mysql> select * from test;
ERROR 1146 (42S02): Table 'mysql.test' doesn't exist
优化器

经过预处理过后的SQL说明没啥毛病了,接下来MySQL就会对这条SQL进行优化,怎么个优化法呢?

第一,假如表里有很多索引的时候,优化器会基于查询成本来考虑使用哪一个索引

select * from product where id = 1为栗子,id一般都会设置主键索引,所以这条SQL就会走主键索引,而不是扫描全表

在这里插入图片描述

如果查询计划没有找到可以优化的计划,就会走全表扫描

在这里插入图片描述

如果现在product有两个索引为id主键索引和作用在name的二级索引

select id from product where id > 1 and name like 'i%'会怎么进行呢?

是使用主键索引还是二级索引?

如果这条SQL走主键索引,那在定位到id > 1的记录还是得回表查,name是否符合条件比较耗时

但是如果使用作用在name上的二级索引,可以使用到覆盖索引(select查询的字段,刚好在索引上),二级索引叶子节点挂的都是当前记录的id,所以使用name的二级索引不需要回表查,可以直接返回要查询的值

在这里插入图片描述

执行器

等优化器决定完这条SQL的执行计划后,执行器就要访问存储引擎,进行数据查询了

主键索引查询

select * from product where id = 1为栗子

由于使用到了主键索引天然具有唯一性,并且是等值查询,就注定了查询返回的结果只有一条

执行流程

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

索引下推查询

现在建立一个联合索引(name, age)

img

现在有下面这条查询语句:

select * from t_user  where age > 20 and reward = 100000;

当联合索引遇到范围查询(>, <)就会停止匹配,也就是age字段能用到联合索引,但是reward字段则无法使用到联合索引

不使用索引下推的流程

  1. Server层首先调用存储引擎的接口定位到满足查询条件的第一条二级索引记录,也就是定位到符合age>20的第一条记录
  2. 存储引擎根据二级索引B+树快速定位到这条记录后,获取主键值,然后进行回表操作,将完整的记录返回给Server层
  3. Server层对这条记录进行判断是否符合reward = 100000,不符合就跳过这条记录
  4. 接着继续向存储引擎要下一条记录,重复上面的操作,直到Server层获取到所有符合条件的结果,接着Server层将结果返回客户端

使用索引下推流程:

  1. Server层首先调用存储引擎的接口定位到满足查询条件的第一条二级索引记录,也就是定位到符合age>20的第一条记录

  2. 存储引擎根据二级索引B+树快速定位到这条记录后,获取主键值,不进行回表操作,先判断当前联合索引中是否reward = 100000,如果条件不成立,则直接跳过该二级索引。如果成立,则执行回表操作,将完成记录返回给 Server 层。

  3. Server 层在判断其他的查询条件(本次查询没有其他条件)是否成立,如果成立则将其发送给客户端;否则跳过该记录,然后向存储引擎索要下一条记录。

  4. 如此往复,直到存储引擎把表中的所有记录读完。

可以看到,使用了索引下推后,虽然 reward 列无法使用到联合索引,但是因为它包含在联合索引(age,reward)里,所以直接在存储引擎过滤出满足 reward = 100000 的记录后,才去执行回表操作获取整个记录。相比于没有使用索引下推,节省了很多回表操作。

当你发现执行计划里的 Extr 部分显示了 “Using index condition”,说明使用了索引下推。

img

总结

Mysql一条Select语句的执行流程是什么?

  1. 连接器进行管理连接、鉴权
  2. 查询缓存
  3. 解析器进行语法分析,关键词提取等
  4. 执行器进行预处理、优化SQL执行计划、执行SQL等
  5. 执行器调用存储引擎接口获取数据返回给客户端

在这里插入图片描述

参考链接:https://xiaolincoding.com/mysql/base/how_select.html

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

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

相关文章

Transformer模型-用jupyter演示逐步计算attention

学习transformer模型-用jupyter演示如何计算attention&#xff0c;不含multi-head attention&#xff0c;但包括权重矩阵W。 input embedding&#xff1a;文本嵌入 每个字符用长度为5的向量表示&#xff1a; 注意力公式&#xff1a; 1&#xff0c;准备Q K V&#xff1a; 先 生…

车载通信与DDS标准解读系列(4):DDSI-RTPS协议

▎什么是RTPS 在DDS协议中&#xff0c;主要描述了实现数据分发服务的DCPS模型和QoS策略&#xff0c;但是我们还不清楚数据怎样在网络中传输&#xff0c;想要了解这些内容&#xff0c;就需要请出咱们的数据搬运工——RTPS。 RTPS全称是Real-Time Publish-Subscribe Protocol&a…

item_get_desc-获得淘宝商品描述api接口:如何通过接口获取商品信息、订单信息、物流信息可以用于数据分析、商品推荐、行业研究等领域

在当今电商繁荣的时代&#xff0c;淘宝作为中国最大的电商平台之一&#xff0c;拥有海量的商品信息。然而&#xff0c;如何高效地获取并利用这些信息&#xff0c;对于商家和开发者来说都至关重要。幸运的是&#xff0c;淘宝开放平台提供了丰富的API接口&#xff0c;其中包括用于…

基于ZooKeeper的Kafka分布式集群搭建与集群启动停止Shell脚本

下载Kafka压缩包 下方是Kafka官网下载地址&#xff0c;本文使用Kafka 3.0.0在虚拟机环境中搭建分布式集群。 Apache Kafka Downloads link 虽然在Kafka 2.8.0之后可以使用KRaft模式搭建高可用的集群以提高数据处理效率&#xff0c;但是目前还有许多企业依然使用ZooKeeper搭建K…

丰诺畅机电科技将莅临2024年第13届生物发酵展

参展企业介绍 无锡丰诺畅机电科技有限公司&#xff0c;是一家分离设备专业制造公司&#xff0c;集开发、设计、制造、销售、服务于一体;具有专业的生产技术&#xff0c;先进的生产工艺&#xff0c;精良的制造设备&#xff0c;完善的检测手段;为满足不同用户的过滤需求&#xf…

酷开科技不断深耕智能电视领域,用酷开系统带给消费者更多可能性

在这个网络快速发展的时代&#xff0c;电视行业也发生了巨大变革。与以往单纯的“看”电视不同&#xff0c;人们不再满足于现有的状态&#xff0c;消费者对电视娱乐的追求更加丰富&#xff0c;这也就带给智能电视产业无限的发展可能。酷开科技瞄准这一产业趋势&#xff0c;不断…

大数据毕业设计hadoop+spark旅游推荐系统 旅游可视化系统 地方旅游网站 旅游爬虫 旅游管理系统 计算机毕业设计 机器学习 深度学习 知识图谱

基于hive数据仓库的贵州旅游景点数据分析系统的设计与实现 摘 要 随着旅游业的快速发展和数字化转型&#xff0c;旅游数据的收集和分析变得越来越重要。贵州省作为一个拥有丰富旅游资源的地区&#xff0c;旅游数据的分析对于促进旅游业的发展和提升旅游体验具有重要意义。基…

程序汪10万接的多平台视频分发项目,模拟人工发视频

本项目来自程序汪背后的私活小团队&#xff0c;开发了一个多平台分发视频项目&#xff0c;给粉丝分享一下解决方案和具体项目分开情况付款情况等等细节&#xff0c;希望给想接私活的朋友一些经验参考 程序汪10万接的多平台视频分发项目&#xff0c;模拟人工发视频 视频版本 在 …

RedCap轻量化5G提升生产效率,多领域应用

在工业数字化时代&#xff0c;工业智能化已经成为了各行各业的发展趋势。而在这个过程中&#xff0c;5G作为新一代网络通信技术正逐渐成为工业领域的核心力量。而在5G技术的应用中&#xff0c;RedCap轻量化5G工业网关路由器便是低成本畅享5G的最佳选择。 RedCap轻量化5G工业网…

x-cmd-pkg | broot 是基于 Rust 开发的一个终端文件管理器

简介 broot 是基于 Rust 开发的一个终端文件管理器&#xff0c;它设计用于帮助用户在终端中更轻松地管理文件和目录&#xff0c;使用树状视图探索文件层次结构、操作文件、启动操作以及定义您自己的快捷方式。 同时它还集成了 ls, tree, find, grep, du, fzf 等工具的常用功能…

Github2024-04-03 开源项目日报 Top10

根据Github Trendings的统计,今日(2024-04-03统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目4TypeScript项目2Jupyter Notebook项目2C++项目1Shell项目1Go项目1非开发语言项目1Rust项目1从零开始构建你喜爱的技术 创建周期:21…

【教程】宝塔default.db占用空间几十g解决方法|宝塔占用磁盘空间特别大解决方法|宝塔磁盘被占满怎么清理

目录 一、前言二、排查问题三、解决方法 一、前言 用过宝塔创建网站&#xff0c;大家应该都非常熟悉&#xff0c;但是用随着用的时间越来越多&#xff0c;宝塔所占用的空间也越来越多&#xff0c;不停的加大数据盘都没有用&#xff0c;我原先买了30G够用了&#xff0c;随着时间…