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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

非小米电脑下载小米电脑管家

由于 小米电脑管家 现在新增了机型验证&#xff0c;本篇将分享非小米电脑用户如何绕过机型验证安装 小米电脑管家 首先到小米跨端智联官网 https://hyperos.mi.com/continuity 中下载小米电脑管家 打开官网链接后&#xff0c;直接滑动到底部&#xff0c;点击下载 下载完成后…

鸿蒙OS开发实例:【组件化模式】

组件化一直是移动端比较流行的开发方式&#xff0c;有着编译运行快&#xff0c;业务逻辑分明&#xff0c;任务划分清晰等优点&#xff0c;针对Android端的组件化&#xff1b;与Android端的组件化相比&#xff0c;HarmonyOS的组件化可以说实现起来就颇费一番周折&#xff0c;因为…

数据转换 | Matlab基于GASF格拉姆角和场一维数据转二维图像方法

目录 效果分析基本介绍程序设计参考资料获取方式 效果分析 基本介绍 基于GASF&#xff08;Gramian Angular Summation Field&#xff09;的方法&#xff0c;将一维数据转换为二维图像的步骤描述 标准化数据&#xff1a; 首先&#xff0c;对一维时序数据进行标准化处理&#xf…

canal部署

定义 canal组件是一个基于mysql数据库增量日志解析&#xff0c;提供增量数据订阅和消费&#xff0c;支持将增量数据投递到下游消费者&#xff08;kafka&#xff0c;rocketmq等&#xff09;或者存储&#xff08;elasticearch,hbase等&#xff09;canal感知到mysql数据变动&…

.Net Core/.Net6/.Net8 ,启动配置/Program.cs 配置

.Net Core/.Net6/.Net8 &#xff0c;启动配置/Program.cs 配置 没有废话&#xff0c;直接上代码调用 没有废话&#xff0c;直接上代码 /// <summary>/// 启动类/// </summary>public static class Mains{static IServiceCollection _services;static IMvcBuilder _…

2012年认证杯SPSSPRO杯数学建模D题(第一阶段)人机游戏中的数学模型全过程文档及程序

2012年认证杯SPSSPRO杯数学建模 减缓热岛效应 D题 人机游戏中的数学模型 原题再现&#xff1a; 计算机游戏在社会和生活中享有特殊地位。游戏设计者主要考虑易学性、趣味性和界面友好性。趣味性是本质吸引力&#xff0c;使玩游戏者百玩不厌。网络游戏一般考虑如何搭建安全可…

【leetcode】将x减到0的最小操作数/水果成篮/找到字符串中所有字母异位词{史上最容易懂的解析}

文章目录 1.将x减到0的最小操作数2.水果成篮3.找到字符串中所有字母异位词 1.将x减到0的最小操作数 分析题目 x不断地减去数组两端的值 看能否减到0&#xff1b;是不是就是在问&#xff1a;nums数组中存不存在【左端右端】组成的连续区间&#xff0c;区间上数的和为x 继续分析 …

EXCEL地理数据处理工具(地图任务)

版本号 作者 修订内容 发布日期 1.0 小O 更新至0705版 2022-4-28 1.1 小O 更新至0772版 2024年4月3日 一、概述 小O地图EXCEL插件版提供基于EXCEL表格进行地理数据处理、地图可视化、地图绘图等功能&#xff0c;地理工具是用户使用频率很高的功能模块。地理工具能…

hadoop:案例:将顾客在京东、淘宝、多点三家平台的消费金额汇总,然后先按京东消费额排序,再按淘宝消费额排序

一、原始消费数据buy.txt zhangsan 5676 2765 887 lisi 6754 3234 1232 wangwu 3214 6654 388 lisi 1123 4534 2121 zhangsan 982 3421 5566 zhangsan 1219 36 45二、实现思路&#xff1a;先通过一个MapReduce将顾客的消费金额进行汇总&#xff0c;再通过一个MapReduce来根据金…

easyExcel 模版导出 中间数据纵向延伸,并且对指定列进行合并

想要达到的效果 引入maven引用 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.2.1</version></dependency> 按照要求创建模版 备注 : 模板注意 用{} 来表示你要用的变量 如果本…

【Spring】使用@Bean和@Import注解配置Bean,与Bean的实例化

目录 1、bean是什么 2、配置bean 2.1、使用Bean注解配置Bean 2.2、使用Import注解配置Bean 3、实例化Bean 1、bean是什么 在 Spring 中&#xff0c;Bean 是指由 Spring 容器管理的对象。Spring IOC 容器负责创建、配置和管理这些 Bean 对象的生命周期。Spring IOC 容器会管…

网络基础二——传输层协议UDP与TCP

九、传输层协议 ​ 传输层协议有UDP协议、TCP协议等&#xff1b; ​ 两个远端机器通过使用"源IP"&#xff0c;“源端口号”&#xff0c;“目的IP”&#xff0c;“目的端口号”&#xff0c;"协议号"来标识一次通信&#xff1b; 9.1端口号的划分 ​ 0-10…

Spring Boot中前端通过请求接口下载后端存放的Excel模板

导出工具类 package com.yutu.garden.utils;import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import org.apache.commons.io.IOUtils; import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.slf4j.Logger;…

06-编辑器

gedit编辑器 gedit是Ubuntu系统自带的编辑器&#xff0c;可以用来轻度编辑和记录一些内容。 在终端中我们通过以下命令打开&#xff1a; gedit 要打开或者新建的文件名虽然Ubuntu的图形界面也能通过gedit打开文件&#xff0c;但是用终端打开gedit可以动用更高的权限&#xff…

OpenHarmony实战开发-使用一次开发多端部署实现一多设置典型页面

介绍 本示例展示了设置应用的典型页面&#xff0c;其在小窗口和大窗口有不同的显示效果&#xff0c;体现一次开发、多端部署的能力。 1.本示例使用一次开发多端部署中介绍的自适应布局能力和响应式布局能力进行多设备&#xff08;或多窗口尺寸&#xff09;适配&#xff0c;保…

掌握机器学习新星:使用Python和Scikit-Learn进行图像识别

正文&#xff1a; 随着智能手机和社交媒体的普及&#xff0c;图像数据的生成速度比以往任何时候都快。为了自动化处理这些数据&#xff0c;我们需要强大的图像识别系统。机器学习提供了一种有效的方法来识别和分类图像中的对象。Scikit-Learn是一个流行的Python库&#xff0c;它…

谷粒商城实战(010 缓存-解决数据一致性问题以及SpringCache的使用)

Java项目《谷粒商城》架构师级Java项目实战&#xff0c;对标阿里P6-P7&#xff0c;全网最强 总时长 104:45:00 共408P 此文章包含第166p-第p172的内容 缓存一致性问题解决 redisson使用lua脚本&#xff0c;所以的锁都保证了原子性 改之前的代码 锁的粒度越小越好 如11号…

PS入门|黑白色的图标怎么抠成透明背景

前言 抠图可以算是PS的入门必备操作&#xff0c;开始学习PS的小伙伴可以根据本帖子推荐一步步学习哦&#xff01;但切勿心急&#xff5e; 今天给小伙伴们带来&#xff1a;黑白色的图标抠图教程 抠图有很多种方法&#xff0c;但根据类型的不同&#xff0c;使用适当的方法很重…

Redis底层数据结构-Dict

1. Dict基本结构 Redis的键与值的映射关系是通过Dict来实现的。 Dict是由三部分组成&#xff0c;分别是哈希表&#xff08;DictHashTable&#xff09;&#xff0c;哈希节点&#xff08;DictEntry&#xff09;&#xff0c;字典&#xff08;Dict&#xff09; 哈希表结构如下图所…

YUNBEE云贝-2024年4月PostgreSQL PGCM认证实战培训

课程介绍 了解关注开源技术&#xff0c;学习PG以点带面 Linux/Andriod&#xff08;操作系统&#xff09;、Apache/Tomcat&#xff08;应用服务器&#xff09;、OpenStack/KVM&#xff08;虚拟化&#xff09;、Docker/K8S&#xff08;容器化&#xff09;、Hadoop&#xff08;大…