总结:
顺序大概是这样: PyMysql(或JDBC)连接数据库 > 连接池 > SQL接口 > 查询缓存(8.0移除) > 解析器 > 优化器 > 存储引擎 > 数据文件
那服务器进程对客户端进程发送的请求做了什么处理,才能产生最后的处理结果呢?这里以查询请求为例展示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TNVnAhmX-1665847189925)(img.png)]
标准图为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VzQj4Oeh-1665847189927)(img_1.png)]
Connectors: MySQL服务器之外的客户端程序,和具体编程语言相关的内容
Management Service &Utilities–>基础服务组件: MySQL服务器的基础服务组件
Connection Pool -->连接池: 提供了多个用于客户端和服务器端进行交互的线程,这些线程使用完后交还到连接池,供其他客户端使用,从而保证资源不被浪费
SQL Interface–>SQL接口: 作用是用来接收SQL指令并返回查询结果
Parser–>解析器: 用来解析SQL接口中的SQL,分为语法解析和语义解析。解析后会生成一个语法树,该语法树可用于后续的查询优化。解析器将SQL语句“肢解”为关键字、表名、字段名等内容
Optimlzer–>优化器: 核心组件,对SQL进行优化:分为逻辑上的优化和物理上的优化。物理优化—使用索引
Cache & Buffers–>查询缓存: 在8.0中已经弃用(命中率过低)。以key -
value的方式缓存查询结果,查询结果作为value,SQL语句作为key。当下一次查询和缓存的查询语句完全一致时查询命中
pluggable Storage Engines–>插件式存储引擎: 与底层的文件系统进行交互
File system–>文件系统
File & Logs–>日志文件
mysql5.7执行顺序
Connectors–>Connection Pool (连接池)–>SQL Interface(SQL接口)–>Cache & Buffers(查询缓存)–>Parser(解析器)–>Optimlzer(
优化器)–>pluggable Storage Engines(插件式存储引擎)–>File system(文件系统)–>Cache & Buffers(查询缓存)–>SQL Interface(
SQL接口)
Connectors,指的是不同语言中与SQL的交互。MySQL首先是一个网络程序,在TCP之上定义了自己的应用层协议。所以要使用MySQL,我们可以编写代码,跟MySQL
Server建立TCP连接,之后按照其定义好的协议进行交互。或者比较方便的办法是调用SDK,比如Native C API、JDBC、PHP等各语言MysQL
Connector,或者通过ODBC。但通过SDK来访问MysQL,本质上还是在TCP连接上通过MySQL协议跟MySQL进行交互。
系统(客户端)访问 MySQL 服务器前,做的第一件事就是建立 TCP 连接。
经过三次握手建立连接成功后, MySQL 服务器对 TCP 传输过来的账号密码做身份认证、权限获取。
Connection Poll 连接池
SQL Interface: SQL接口
Parser: 解析器
Optimizer: 查询优化器
SQL语句在语法解析之后、查询之前会使用查询优化器确定 SQL 语句的执行路径,生成一个执行计划。
这个执行计划表明应该使用哪些索引进行查询(全表检索还是使用索引检索),表之间的连接顺序如何,最后会按照执行计划中的步骤调用存储引擎提供的方法来真正的执行查询,并将查询结果返回给用户。
它使用“ 选取-投影-连接 ”策略进行查询。例如:
SELECT id,name FROM student WHERE gender = '女';
这个SELECT查询先根据WHERE语句进行 选取 ,而不是将表全部查询出来以后再进行gender过滤。 这个SELECT查询先根据id和name进行属性投影
,而不是将属性全部取出以后再进行过滤,将这两个查询条件 连接 起来生成最终查询结果。
Caches & Buffers: 查询缓存组件
插件式存储引擎层( Storage Engines),真正的负责了MySQL中数据的存储和提取,对物理服务器级别维护的底层数据执行操作,
服务器通过API与存储引擎进行通信。不同的存储引擎具有的功能不同,这样我们可以根据自己的实际需要进行选取。
MySQL 8.0.25默认支持的存储引擎如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WMZQptfq-1665847189927)(img_2.png)]
所有的数据,数据库、表的定义,表的每一行的内容,索引,都是存在文件系统上,以文件的方式存在的,并完成与存储引擎的交互。当然有些存储引擎比如InnoDB,也支持不使用文件系统直接管理裸设备,但现代文件系统的实现使得这样做没有必要了。在文件系统之下,可以使用本地磁盘,可以使用DAS、NAS、SAN等各种存储系统。
MySQL架构图本节开篇所示。下面为了熟悉SQL执行流程方便,我们可以简化如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dMch878l-1665847189928)(img_3.png)]
简化为三层结构:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hb2vY3KH-1665847189930)(img_4.png)]
MySQL的查询流程:
查询缓存:Server 如果在查询缓存中发现了这条 SQL 语句,就会直接将结果返回给客户端;如果没有,就进入到解析器阶段。需要说明的是,因为查询缓存往往效率不高,所以在MySQL8.0
之后就抛弃了这个功能。
解析器: 在解析器中对 SQL 语句进行语法分析、语义分析。
如果没有命中查询缓存,就要开始真正执行语句了。
优化器:在优化器中会确定 SQL 语句的执行路径,比如是根据全表检索 ,还是根据索引检索等。
执行器:
调用 InnoDB 引擎接口取这个表的第一行,判断 ID 值是不是1,如果不是则跳过,如果是则将这行存在结果集中;
调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。
执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。
至此,这个语句就执行完成了。对于有索引的表,执行的逻辑也差不多。
SQL 语句在 MySQL 中的流程是: SQL语句→查询缓存→解析器→优化器→执行器 。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mV9zmGCf-1665847189933)(img_7.png)]
前面的结构图很复杂,我们需要抓取最核心的部分:SQL的执行原理。不同的DBMS的SQL的执行原理是相通的,只是在不同的软件中,各有各的实现路径。
既然一条SQL语句会经历不同的模块,那我们就来看下,在不同的模块中。SQL执行所使用的资源(时间)是怎样的。如何在MySQL中对一条
SQL语句的执行时间进行分析。
了解查询语句底层执行的过程:
select @@profiling;或者show variables like ’
%profiling%'查看是否开启计划。开启它可以让MySQL收集在SQL执行时所使用的资源情况,命令如下:
mysql> select @@profiling;
+-------------+
| @@profiling |
+-------------+
| 0 |
+-------------+
1 row in set, 1 warning (0.00 sec)
mysql> show variables like '%profiling%';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| have_profiling | YES |
| profiling | OFF |
| profiling_history_size | 15 |
+------------------------+-------+
3 rows in set (0.00 sec)
profiling=0 代表关闭,我们需要把 profiling 打开,即设置为 1:
mysql> set profiling=1;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> select @@profiling;
+-------------+
| @@profiling |
+-------------+
| 1 |
+-------------+
1 row in set, 1 warning (0.00 sec)
# 自己创表查询就可
select * from stu
mysql> show profiles;
+----------+------------+--------------------+
| Query_ID | Duration | Query |
+----------+------------+--------------------+
| 1 | 0.00017325 | select @@profiling |
| 2 | 0.00006500 | ls |
| 3 | 0.00008050 | show databasesl |
| 4 | 0.00101550 | show databases |
| 5 | 0.00016350 | SELECT DATABASE() |
| 6 | 0.00066025 | show databases |
| 7 | 0.00079000 | show tables |
| 8 | 0.00093575 | show tables |
| 9 | 0.00027300 | select * from stu |
| 10 | 0.00023475 | select * from stu |
| 11 | 0.00027475 | select * from stu |
+----------+------------+--------------------+
11 rows in set, 1 warning (0.00 sec)
mysql> show profile;
+--------------------------------+----------+
| Status | Duration |
+--------------------------------+----------+
| starting | 0.000066 |
| Executing hook on transaction | 0.000005 |
| starting | 0.000009 |
| checking permissions | 0.000006 | # 权限检查
| Opening tables | 0.000034 | # 打开表
| init | 0.000006 | # 初始化
| System lock | 0.000010 | # 锁系统
| optimizing | 0.000005 | # 优化查询
| statistics | 0.000016 |
| preparing | 0.000019 | # 准备
| executing | 0.000050 | # 执行
| end | 0.000004 |
| query end | 0.000003 |
| waiting for handler commit | 0.000009 |
| closing tables | 0.000008 |
| freeing items | 0.000019 |
| cleaning up | 0.000009 |
+--------------------------------+----------+
17 rows in set, 1 warning (0.00 sec)
# 也可以指定查询ID 如果不指定就是查询最新的一条
show profile for query 10;
# 除了sql执行时间以外还可以查询更丰富的内容
show profile cpu,block io for query 11;
随着Mysql版本的更新换代,其优化器也在不断的升级,优化器会分析不同执行顺序产生的性能消耗不同而动态调整执行顺序。
需求:查询每个部门年龄高于20岁的人数且高于20岁人数不能少于2人,显示人数最多的第一名部门信息下面是经常出现的查询顺序:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fJNmbHTn-1665847189935)(img_8.png)]
for query 10;
show profile cpu,block io for query 11;
## 2.3 SQL语法顺序
随着Mysql版本的更新换代,其优化器也在不断的升级,优化器会分析不同执行顺序产生的性能消耗不同而动态调整执行顺序。
需求:查询每个部门年龄高于20岁的人数且高于20岁人数不能少于2人,显示人数最多的第一名部门信息下面是经常出现的查询顺序:
[外链图片转存中...(img-fJNmbHTn-1665847189935)]