MySQL性能优化——MYSQL执行流程

2023-09-18 05:53:25

MySQL 执行流程1-5如下图。
在这里插入图片描述

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

  • Server 层负责建立连接、分析和执行 SQL。MySQL 大多数的核心功能模块都在这实现,主要包括连接器,查询缓存、解析器、预处理器、优化器、执行器等。另外,所有的内置函数(如日期、时间、数学和加密函数等)和所有跨存储引擎的功能(如存储过程、触发器、视图等。)都在 Server 层实现。
  • 存储引擎层负责数据的存储和提取。支持 InnoDB、MyISAM、Memory 等多个存储引擎,不同的存储引擎共用一个 Server 层。现在最常用的存储引擎是 InnoDB,从 MySQL 5.5 版本开始, InnoDB 成为了 MySQL 的默认存储引擎。我们常说的索引数据结构,就是由存储引擎层实现的,不同的存储引擎支持的索引类型也不相同,比如 InnoDB 支持索引类型是 B+树 ,且是默认使用,也就是说在数据表中创建的主键索引和二级索引默认使用的是 B+ 树索引。

第一步:连接器,客户端和服务器端建立TCP连接

通过在命令行敲如下命令,开启mysql服务

mysql -h$ip -u$user -p$password

连接的过程需要先经过 TCP 三次握手,因为 MySQL 是基于 TCP 协议进行传输的,如果 MySQL 服务并没有启动,则会收到如下的报错:
在这里插入图片描述

如果 MySQL 服务正常运行,完成 TCP 连接的建立后,连接器就要开始验证你的用户名和密码,如果用户名或密码不对,就收到一个"Access denied for user"的错误,然后客户端程序结束执行。

如果用户密码都没有问题,连接器就会获取该用户的权限,然后保存起来,后续该用户在此连接里的任何操作,都会基于连接开始时读到的权限进行权限逻辑的判断。

所以,如果一个用户已经建立了连接,即使管理员中途修改了该用户的权限,也不会影响已经存在连接的权限。修改完成后,只有再新建的连接才会使用新的权限设置。

查看 MySQL 服务被多少个客户端连接了?

如果你想知道当前 MySQL 服务被多少个客户端连接了,你可以执行 show processlist 命令进行查看。
在这里插入图片描述

比如上图的显示结果,共有两个用户名为 root 的用户连接了 MySQL 服务,其中 id 为 6 的用户的 Command 列的状态为 Sleep ,这意味着该用户连接完 MySQL 服务就没有再执行过任何命令,也就是说这是一个空闲的连接,并且空闲的时长是 736 秒( Time 列)

空闲连接会一直占用着吗?

MySQL 定义了空闲连接的最大空闲时长,由 wait_timeout 参数控制的,默认值是 8 小时(28880秒),如果空闲连接超过了这个时间,连接器就会自动将它断开。

mysql> show variables like 'wait_timeout';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout  | 28800 |
+---------------+-------+
1 row in set (0.00 sec)

当然,我们自己也可以手动断开空闲的连接,使用的是 kill connection + id 的命令。

mysql> kill connection +6;
Query OK, 0 rows affected (0.00 sec)

一个处于空闲状态的连接被服务端主动断开后,这个客户端并不会马上知道,等到客户端在发起下一个请求的时候,才会收到这样的报错“ERROR 2013 (HY000): Lost connection to MySQL server during query”。

MySQL 的连接数有限制吗?

MySQL 服务支持的最大连接数由 max_connections 参数控制,比如我的 MySQL 服务默认是 151 个,超过这个值,系统就会拒绝接下来的连接请求,并报错提示“Too many connections”。

mysql> show variables like 'max_connections';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 151   |
+-----------------+-------+
1 row in set (0.00 sec)

MySQL 的连接也跟 HTTP 一样,有短连接和长连接的概念,它们的区别如下:

// 短连接
连接 mysql 服务(TCP 三次握手)
执行sql
断开 mysql 服务(TCP 四次挥手)

// 长连接
连接 mysql 服务(TCP 三次握手)
执行sql
执行sql
执行sql
....
断开 mysql 服务(TCP 四次挥手)

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

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

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

有两种解决方式。

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

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

第二步:查询缓存,如果是SELECT语句就查缓存

建立连接后,客户端向 MySQL 服务发送 SQL 语句,MySQL 服务收到 SQL 语句后,就会解析出 SQL 语句的第一个字段,看看是什么类型的语句

如果 SQL 是查询语句(select 语句),MySQL 就会先去查询缓存( Query Cache )里查找缓存数据,看看之前有没有执行过这一条命令,这个查询缓存是以 key-value 形式保存在内存中的,key 为 SQL 查询语句,value 为 SQL 语句查询的结果。

如果查询的语句命中查询缓存,那么就会直接返回 value 给客户端。如果查询的语句没有命中查询缓存中,那么就要往下继续执行,等执行完后,查询的结果就会被存入查询缓存中。

为什么mysql8.0没有查询缓存功能

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

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

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

TIP
这里说的查询缓存是 server 层的,也就是 MySQL 8.0 版本移除的是 server 层的查询缓存,并不是 Innodb 存储引擎中的 buffer pool。

第3步:解析 SQL

在正式执行 SQL 查询语句之前, MySQL 会先对 SQL 语句做解析
解析器会做如下两件事情。

词法分析

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

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

img

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

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

更多推荐

如何理解JavaScript定时器的4种写法-附带面试题讲解

在JavaScript里,我们已经会使用一些原生提供的方法来实现需要延时执行的操作代码,比如很多在线时钟的制作,图片轮播的实现,还有一些广告弹窗,但凡可以自动执行的东西,都是可以和定时器有关的。今天就来和大家分享一下,关于我们在JavaScript里经常会使用到的定时器方法在JavaScript里,我们要学习四个定时器

基于GBDT+Tkinter+穷举法按排队时间预测最优路径的智能导航推荐系统——机器学习算法应用(含Python工程源码)+数据集(三)

目录前言总体设计系统整体结构图系统流程图运行环境Python环境Pycharm环境Scikit-learnt模块实现1.数据预处理2.客流预测3.百度地图API调用4.GUI界面设计1)手绘地图导入2)下拉菜单设计3)复选框设计4)最短路径结果输出界面设计5)智能推荐结果输出设计6)界面展示5.路径规划6.智能推荐相关

【C++】内联函数 ③ ( C++ 编译器 不一定允许内联函数的内联请求 | 内联函数的优缺点 | 内联函数 与 宏代码片段对比 )

文章目录一、内联函数不一定成功1、内联函数的优缺点2、C++编译器不一定允许内联函数的内联请求3、是否内联决定权在编译器手中二、内联函数与宏代码片段对比1、内联函数2、宏代码片段一、内联函数不一定成功1、内联函数的优缺点"内联函数"不是在运行时调用的,"内联函数"是编译时将函数体对应的CPU指令直接嵌入到调用该函数的地

【表格插入小计行】el-table表格,数组对象中根据某字段插入小计行计算数据

前言功能解释:遇到的一个需求,是表格的tabledata数组。里面有科室医生还有很多消费指标等数据。然后需要我排序后把科室放在一起。然后在每个科室下面添加一行数据,是小计行。用于计算上面相同科室的所有数据汇总。然后最下面再来个合计行,加上所有的小计。效果图刚排序后是这样的表格样子,数据是我模拟的然后插入小计行后是这样的

JavaScript事件流:深入理解事件处理和传播机制

🎬岸边的风:个人主页🔥个人专栏:《VUE》《javaScript》⛺️生活的理想,就是为了理想的生活!目录引言1.事件流的发展流程1.1传统的DOM0级事件1.2DOM2级事件和addEventListener方法1.3W3CDOM3级事件1.4React与VirtualDOM2.事件流的属性2.1事件捕获阶段2.

《从菜鸟到大师之路 Redis 篇》

《从菜鸟到大师之路Redis篇》(一):Redis基础理论与安装配置Nosql数据库介绍是一种非关系型数据库服务,它能解决常规数据库的并发能力,比如传统的数据库的IO与性能的瓶颈,同样它是关系型数据库的一个补充,有着比较好的高效率与高性能。专注于key-value查询的redis、memcached、ttserver。

transformer大语言模型(LLM)部署方案整理

说明大模型的基本特征就是大,单机单卡部署会很慢,甚至显存不够用。毕竟不是谁都有H100/A100,能有个3090就不错了。目前已经有不少框架支持了大模型的分布式部署,可以并行的提高推理速度。不光可以单机多卡,还可以多机多卡。我自己没啥使用经验,简单罗列下给自己备查。不足之处,欢迎在评论区指出。框架名称出品方开源地址Fa

JWT 令牌撤销:中心化控制与分布式Kafka处理

【squids.cn】全网zui低价RDS,免费的迁移工具DBMotion、数据库备份工具DBTwin、SQL开发工具等令牌对于安全数字访问至关重要,但如果您需要撤销它们怎么办?尽管我们尽了最大努力,但有时代币可能会被泄露。这可能是由于编码错误、意外记录、零日漏洞和其他因素造成的。令牌撤销是现代安全性的一个重要方面,确

并发编程——synchronized

文章目录原子性、有序性、可见性原子性有序性可见性synchronized使用synchronized锁升级synchronized-ObjectMonitor原子性、有序性、可见性原子性数据库事务的原子性:是一个最小的执行的单位,一次事务的多次操作要么都成功,要么都失败。并发编程的原子性:一个或多个指令在CPU执行过程

【无公网IP内网穿透】 搭建Emby媒体库服务器并远程访问「家庭私人影院」

目录1.前言2.Emby网站搭建2.1.Emby下载和安装2.2Emby网页测试3.本地网页发布3.1注册并安装cpolar内网穿透3.2Cpolar云端设置3.3Cpolar内网穿透本地设置4.公网访问测试5.结语1.前言在现代五花八门的网络应用场景中,观看视频绝对是主力应用场景之一,加上移动网络技术的发展,随时随地

vue3.2+ts封装axios

1.创建utils文件夹/server下面创建index.ts,代码如下:importaxios,{AxiosRequestConfig}from"axios";import{BASE_URL,TIMEOUT}from"@/config/axios";/***@说明接口请求返回信息(按照自己的实际情况分配基础请求格式)

热文推荐