【MySQL从入门到精通】【高级篇】(五)MySQL的SQL语句执行流程

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
全局流量管理 GTM,标准版 1个月
简介: 今天正式进入核心知识点的学习,本文主要介绍MySQL中SQL的执行流程。熟悉SQL的执行流程对后期数据库的优化至关重要。话不多说直接进入今天的学习。

1. 简介

今天正式进入核心知识点的学习,本文主要介绍MySQL中SQL的执行流程。熟悉SQL的执行流程对后期数据库的优化至关重要。话不多说直接进入今天的学习。

2. 环境

环境 版本
Red Hat 4.8.5-39
MySQL 5.7

SQL执行流程

SQL语句在MySQL中的执行流程,大体可以分为:

客户端将一条SQL语句传给MySQL服务器之后,如果打开了查询缓存的设置,则首先查询缓存,如果没有打开查看缓存或者缓存没命中的话则接着通过解析器解析该SQL语句,解析完成之后就是优化器对SQL语句进行优化,优化完成之后就是执行器执行该SQL语句,并将执行结果返回给客户端。

详细执行流程

SQL语句的详细执行流程如下图所示:

1. 查询缓存

开启查询缓存设置的情况,MySQL5.7默认是不开启的,MySQL8.0):

Server如果在查询缓存中发现了这条SQL语句,就会直接将结果返回给客户端;如果没有,就进入到解析器阶段。需要说明的是,因为查询缓存往往效率不高(命中率不高),所以在MySQL8.0之后就抛弃了这个功能。另外,MySQL5.7 默认是不开启查询缓存的。


MySQL拿到一个查询请求后,会先到查询缓存看看,之前是不是执行过这条语句,之前执行过的语句及结果可能会以key-value对的形式,被直接缓存到内存中。key是查询的语句,value是查询的结果,如果你的查询能够直接在这个缓存中找到key,那么这个value就会被直接返回给客户端。如果查询语句不在查询缓存中,就会继续后面的执行阶段,执行完成后,执行结果会被存入查询缓存中。所以,如果查询命令缓存,MySQL不需要执行后面的复杂操作,就可以直接返回结果,这个效率很高。

但是。。。。。。。。。。

大多数情况下,查询缓存就是一个鸡肋,主要有如下几个原因:


查询命中率不高,

在MySQL中的查询缓存,不是缓存查询计划,而是查询对应的结果,只有相同的查询操作才会命令查询缓存。两个查询请求在任何字符上的不同(例如:空格、注释、大小写),都会导致缓存不会被命中,因此MySQL的查询缓存命中率不高。

如果查询请求中包含某些系统函数、用户自定义函数和函数,比如NOW() 函数,每次调用都会产生罪行的当前时间,每次都不能命中查询缓存。

查询失效时间短

如果是频繁修改的表,查询缓存也会被被频繁的修改,这样反而加大系统的消耗,导致缓存频繁失效。

总之,因为查询缓存弊大于利,查询缓存的失效非常频繁。

一般建议大家在静态表里使用查询缓存,所谓的静态表,就是极少被更新的数据表,比如:一个系统的配置表,字典表,这张表上的查询才适合使用查询缓存。

查看查询缓存是否开启

在MySQL 5.7中通过如下命令查看当前MySQL实例是否开启缓存机制

show variables like 'query_cache_type';

默认情况是不开启的,后面会详细介绍如何开启查询缓存。query_cache_type 有三个值,0代表关闭查询缓存OFF,1代表开启ON,2表示按需开启,如果设置为2的话,当需要使用到查询缓存时,可以使用 SQL_CACHE,像下面这个语句一样:

SELECT SQL_CACHE * FROM test WHERE ID=10;

监控查询缓存的命中率

通过下面的命令可以监控查询缓存的命中率:

show status like '%Qcache%';

运行结果解析:

Qcache_free_blocks: 表示查询缓存中还有多少剩余的blocks,如果该值显示较大,这说明查询缓存中的内存碎片过多,可能在一定的时间进行整理。

Qcache_free_memory: 查询缓存的内存大小,通过这个参数可以很清晰的指导当前系统的查询内存是否够用,是多了,还是不够用,DBA可以根据实际情况做出调整。

Qcache_hits: 表示有多少次命令缓存,我们主要可以通过该值来验证我们的查询缓存的效果,数字越大,缓存效果越理想。

2. 解析器

在解析器中对SQL语句进行语法分析,语义分析

如果没有命令查询缓存,就要开始真正执行语句了。首先,MySQL需要知道你要做什么,因此需要对SQL语句做解析,SQL语句的分析分为词法分析与语法分析。

分析器先做**“词法分析”**,你输入的是由多个字符串和空格组成的一条SQL语句,MySQL需要识别出里面的字符串分别是什么,代表什么。


MySQL从你输入的SELECT 这个关键字识别出来,这是一个查询语句,它也要把字符串"T" 识别成"表名T",把字符串"ID" 识别成"列ID"。

接着,要做"语法分析"。根据词法分析的结果,语法分析器(比如:Bison)会根据语法规则,判断你输入的这个SQL语句是否满足SQL语法。

如果你的语句不对,就会收到"You have an error in your SQL syntax" 的错误提示,比如下面这个语句"from" 写成了 “fro”。

mysql> SELECT * FRO test WHERE ID=1;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FRO test WHERE ID=1' at line 1

如果SQL语句正确,则会生成一个这样的语法树:

以如下SQL进行说明:

SELECT username,age FROM userinfo WHERE age>20 and level>5;

下面是SQL词法分析的过程步骤:

解析器的基本工作就是进行词法分析以及语法分析,达到一个语法树,然后交给它的下游。

3. 优化器

在优化器中会确定SQL语句的执行路径,比如是根据 全表检索,还是根据 索引检索等。

经过解析器,MySQL就知道你要做什么,在开始执行之前,还要先经过优化器的处理,一条查询可以有很多种执行方式,最后都返回相同的结果。优化器的作用就是找到这其中最好的执行计划。


比如:优化器是在表里面多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联(join)的时候决定各个表的连接顺序,还有表达式简化、子查询转为连接,外连接转为内连接等。

举例:如下语句是执行两个表的join;

SELECT * FROM test1 join test2 using(ID)
  WHERE test1.name='zhangsan' and test2.name='MySQL从入门到精通课程';

方案一:可以先从表test1里面取出name=‘zhangsan’的记录ID值,在根据ID值关联表test2,在判断test2里面name的值是否等于’MySQL从入门到精通课程’。


方案二:可以先从表test2里面取出name='MySQL从入门到精通课程’的记录的ID值,再根据ID值关联到test1,再判断test1里面name的值是否等于zhangsan。


这两种执行方法的逻辑结果是一样的,但是执行的效率会有所不同,而优化器的作用就是决定选择使用哪一种方案,优化器阶段完成后, 这个语句的执行方案就确定下来了,然后进入执行器阶段。


在查询优化器中,可以分为逻辑查询优化阶段和物理查询优化阶段。


逻辑查询优化就是通过改变SQL语句的内容来使得SQL查询更高效,同时为物理查询优化提供更多的候选执行计划。通常采用的方式是对SQL语句进行等价变换,对查询进行重写,而查询重写的数学基础就是关系代数。对条件表达式进行等价谓词重写、条件简化,对视图进行重写,对子查询进行优化,对连接语义进行了外连接消除,嵌套连接消除等。


物理查询优化是基于关系代数进行的查询重写,而关系代数的每一步都对应着物理计算,这些物理计算往往存在多种算法,因此需要计算各种物理路径的代价,从而选择代价最小的作为执行计划。在这个阶段里,对于单表和多表连接的操作,需要高效地使用索引,提升查询效率。

4. 执行器:

截止到目前,还没有真正去读写真实的表,仅仅只是产生了一个执行计划,于是就进入了执行器阶段。

在执行之前需要判断该用户是由具备权限,如果没有,就会返回权限错误。如果具备权限,就执行SQL查询并返回结果。在MySQL8.0以下的版本,如果设置了查询缓存,这时会将查询结果进行缓存。

SELECT * FROM test WHERE id=1;

如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,调用存储引擎API对表进行读写。存储引擎API只是抽象接口,下面还有个存储引擎层,具体实现还是要看表选择的存储引擎。


比如:表test中,ID字段没有索引,那么执行器的执行流程是这样的:

调用InnoDB引擎接口取这个表的第一行,判断ID值是不是1,如果不是则跳过,如果是则将这行存在结果集中;调用引擎接口取"下一行",重复相同的判断逻辑,直到取到这个表的最后一行。


执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。


至此,这个语句就执行完成了,对于有索引的表,执行的逻辑也差不多。

SQL执行流程的演示

既然一条SQL语句会经历不同的模块,那我们就来看下,在不同的模块下,SQL执行所使用的资源(时间)是怎样的。如何在MySQL中对一条SQL语句的执行时间进行分析。

1. 确认profiling是否开启

了解查询语句底层执行的过程:select @@profiling; 或者show variables like '%profiling%' 查看是否开启计划。开启它可以让MySQL收集在SQL执行时所使用的资源情况,命令如下:

# 默认查询的是session级别的,如果要查询全局级别的则可以使用 select @@global.profiling;
mysql> select @@profiling;
mysql> show variables like 'profiling';

profiling=0代表关闭,我们需要把profiling打开,即设置为1;

mysql> set profiling=1;

Profiling功能由MySQL会话变量:profiling控制,默认是OFF(关闭状态)。

2. 多次执行相同SQL查询

然后我们执行任意一个SQL查询。

SELECT * FROM customer limit 10

接着就是通过如下命令查看每条SQL的执行时间。

mysql> show profiles;

如果要查看最近一条SQL语句的具体执行计划可以通过如下命令;

mysql> show profile;

这里详细展示了SQL语句SELECT * FROM customer limit 100; 在每一步的执行耗时,包括开始,检查权限,打开数据表,初始化,系统锁等等。

如果要查询具体某条SQL的详细执行情况可以通过如下命令;

mysql> show profile for query [Query_ID];

比如查询Query_ID为4的SQL语句的执行情况。

开启查询缓存

1. 在配置文件开启查询缓存

/etc/my.cnf 中新增一行:

query_cache_type=1

2.重启mysql服务

systemctl restart mysqld
• 1

3.开启查询执行计划

由于重启过服务,需要重新执行如下指令,开启profiling。

mysql> set profiling=1;
• 1

4.执行语句两次:

mysql>SELECT * FROM stock LIMIT 100;
mysql>SELECT * FROM stock LIMIT 100;

执行之后查询SQL语句的总耗时,发现第二次执行时的总耗时明显比第一执行时要短很多。

在分别查看SQL语句在每个环节中的耗时,发现第一次执行SQL语句时共有29个状态

而第二次执行时只有9个状态,并且可以看到 sending cached result to client 这个状态,故,第二次查询是从查询缓存中直接返回数据。

当然,profile命令除了查询耗时,还可以查询每个阶段耗费cpu,io的情况。

需要注意的是SQL语句必须完全一致才能命中缓存,否则不能命中缓存。

现在将上面的那个查询语句稍微修改下;

SELECT * from  stock LIMIT 1000

将form改成小写,在from和stock之间增加空格,发现不能命中缓存。

总结

熟练掌握SQL的执行流程非常非常的重要!!

本文主要就是三点;

1.不建议开启查询缓存

2.SQL的执行过程主要是:SQL语句–>查询缓存–>解析器—>优化器—>执行器

3.通过 select profiles可以查询所有sql的执行耗时,通过select profile 可以查询最近一条sql的每个阶段的耗时

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1天前
|
SQL 存储 缓存
MySQL执行流程
本文介绍了MySQL的执行流程,分为server层和引擎层。server层包含连接器、查询缓存、解析器、预处理器、优化器等组件,负责SQL的接收、解析、优化及执行;引擎层负责数据的存储与读取。文章详细解释了各组件的功能,如连接器负责用户身份认证,查询缓存提高查询效率,解析器进行SQL的词法和语法分析,预处理器验证表和字段的存在性,优化器选择最优执行计划,最终由查询执行引擎完成查询并将结果返回给客户端。
MySQL执行流程
|
7天前
|
SQL 存储 缓存
MySQL进阶突击系列(02)一条更新SQL执行过程 | 讲透undoLog、redoLog、binLog日志三宝
本文详细介绍了MySQL中update SQL执行过程涉及的undoLog、redoLog和binLog三种日志的作用及其工作原理,包括它们如何确保数据的一致性和完整性,以及在事务提交过程中各自的角色。同时,文章还探讨了这些日志在故障恢复中的重要性,强调了合理配置相关参数对于提高系统稳定性的必要性。
|
5天前
|
SQL 关系型数据库 MySQL
MySQL 高级(进阶) SQL 语句
MySQL 提供了丰富的高级 SQL 语句功能,能够处理复杂的数据查询和管理需求。通过掌握窗口函数、子查询、联合查询、复杂连接操作和事务处理等高级技术,能够大幅提升数据库操作的效率和灵活性。在实际应用中,合理使用这些高级功能,可以更高效地管理和查询数据,满足多样化的业务需求。
26 3
|
8天前
|
SQL 关系型数据库 MySQL
MySQL导入.sql文件后数据库乱码问题
本文分析了导入.sql文件后数据库备注出现乱码的原因,包括字符集不匹配、备注内容编码问题及MySQL版本或配置问题,并提供了详细的解决步骤,如检查和统一字符集设置、修改客户端连接方式、检查MySQL配置等,确保导入过程顺利。
|
10天前
|
SQL 存储 关系型数据库
MySQL进阶突击系列(01)一条简单SQL搞懂MySQL架构原理 | 含实用命令参数集
本文从MySQL的架构原理出发,详细介绍其SQL查询的全过程,涵盖客户端发起SQL查询、服务端SQL接口、解析器、优化器、存储引擎及日志数据等内容。同时提供了MySQL常用的管理命令参数集,帮助读者深入了解MySQL的技术细节和优化方法。
|
11天前
|
SQL Oracle 关系型数据库
SQL(MySQL)
SQL语言是指结构化查询语言,是一门ANSI的标准计算机语言,用来访问和操作数据库。 数据库包括SQL server,MySQL和Oracle。(语法大致相同) 创建数据库指令:CRATE DATABASE websecurity; 查看数据库:show datebase; 切换数据库:USE websecurity; 删除数据库:DROP DATABASE websecurity;
|
1月前
|
存储 SQL NoSQL
|
1月前
|
SQL 关系型数据库 MySQL
MySql5.6版本开启慢SQL功能-本次采用永久生效方式
MySql5.6版本开启慢SQL功能-本次采用永久生效方式
42 0
|
SQL 存储 关系型数据库
MySQL下使用SQL命令进行表结构与数据复制实践
MySQL下使用SQL命令进行表结构与数据复制实践
157 0
|
SQL 关系型数据库 MySQL
MySQl数据库第八课-------SQL命令查询-------主要命脉2
MySQl数据库第八课-------SQL命令查询-------主要命脉