【MySQL】MySQL查询语句是如何执行的(读书笔记)

        在使用mysql时,我们只懂得输入一条查询语句,返回结果,却不知道一条查询语句时如何执行的。

        假如,你有个最简单的表,表里只有一个ID字段,比如执行下面这个查询语句时:

select * from T where ID=10;

        接下来我将拆解一条查询语句的大致执行流程,如下我给出的是Mysql的基本架构图:

     总体而言,MySQL可以分为两个主要部分:Server层和存储引擎层。

        Server层包括连接器、查询缓存、分析器、优化器和执行器等,涵盖了MySQL的核心服务功能。它还包括所有内置函数(如日期、时间、数学和加密函数等),并实现了所有跨存储引擎的功能,如存储过程、触发器和视图等。

        存储引擎层负责数据的存储和提取。MySQL的架构支持多个存储引擎,包括InnoDB、MyISAM、Memory等。目前最常用的存储引擎是InnoDB,从MySQL 5.5.5版本开始成为默认存储引擎。

        换句话说,当你执行CREATE TABLE建表语句时,如果没有指定引擎类型,MySQL将默认使用InnoDB引擎。当然,你也可以通过指定存储引擎类型来选择其他引擎,例如在CREATE TABLE语句中使用ENGINE=MEMORY来指定使用内存引擎创建表。不同的存储引擎具有不同的数据存取方式和支持的功能。

        从图中可以看出,一个server层供多个不同的存储引擎使用。接下来讲详细解释server层中的每个部件是如何执行的。

1.连接器

第一步,连接器负责跟客户端建立连 接、获取权限、维持和管理连接。连接命令一般写作

mysql -h$ip -P$port -u$user -p

其中的命令解释如下

  • $ip: MySQL服务器的IP地址或主机名。
  • $port: MySQL服务器监听的端口号。
  • $user: 要进行身份验证的用户名。
  • -p: 此标志会提示您输入指定用户的密码。

建议不要再-p后明文书写密码

        在连接命令中,"mysql"是一个客户端工具,用于与服务器端建立连接。在经典的TCP握手完成后,连接器会开始验证您的身份,使用您输入的用户名和密码进行认证。

        如果用户名或密码不正确,您将收到一个"Access denied for user"的错误消息,并且客户端程序将终止执行。

        如果用户名和密码认证成功,连接器将从权限表中查找您拥有的权限。随后,在这个连接中进行的权限判断将依赖于此时读取的权限信息。

        这意味着,一旦用户成功建立连接,即使管理员账号修改了该用户的权限,已经存在的连接的权限也不会受到影响。只有在创建新连接时才会使用新的权限设置。

        连接建立完成后,如果没有后续操作,该连接将处于空闲状态。

2.查询缓存

        查询缓存这个功能在mysql8.0之后就被去掉了,原因是这个功能弊大于利,在一些情况下命中率非常低,因此也不建议使用。接下来简单提一提。

        MySQL在接收到查询请求后,首先会检查查询缓存,看之前是否执行过相同的查询语句。之前执行过的语句及其结果可能会以key-value对的形式直接缓存在内存中。如果查询语句在缓存中存在,那么查询结果会直接从缓存中返回给客户端。

        如果查询语句不在查询缓存中,MySQL会继续执行后续的查询阶段。待查询执行完成后,执行结果会被存入查询缓存中。这样,下次如果有相同的查询请求,就可以直接从缓存中获取结果,避免了复杂的查询操作,从而提高了查询的效率。

        通过查询缓存的利用,MySQL能够快速响应那些已经执行过的查询请求,而无需再次执行相同的查询操作,从而提升了整体的查询性能。

        既然能够提升性能,那为何开头说不建议使用呢,其原因如下:

        查询缓存在MySQL中的失效频率很高,只要对某个表进行更新操作,该表上的所有查询缓存都会被清空。因此,即使你费心地将查询结果存入缓存中,但在实际使用之前就可能被一个更新操作全部清空。对于更新频繁的数据库来说,查询缓存的命中率会非常低。除非你的业务场景是针对某个静态表进行查询,且该表的更新频率很低。例如,一个系统配置表,因为该表很长时间才会更新一次,所以适合使用查询缓存。

3.分析器

        当查询缓存未命中时,MySQL开始执行SQL语句。首先,MySQL需要了解你的意图,因此需要对SQL语句进行解析。

        解析过程首先进行词法分析。你输入的SQL语句由多个字符串和空格组成,MySQL需要识别这些字符串代表的含义。例如,MySQL会识别出关键字"select"表示这是一个查询语句,将字符串"T"识别为表名"T",将字符串"ID"识别为列名"ID"。

        完成词法分析后,MySQL进行语法分析。根据词法分析的结果和语法规则,语法分析器判断你输入的SQL语句是否符合MySQL的语法规范。

        如果输入的语句不正确,你将收到一个错误提示,例如"You have an error in your SQL syntax",这表明你的SQL语句存在语法错误。例如,如果输入的语句是"select"缺少了开头的字母"s",就会触发这个错误。

        通过解析和语法分析,MySQL能够识别出SQL语句的结构和含义,从而为后续的执行阶段做准备。

4.优化器

        经过分析器,MySQL能够确定你要执行的操作。在开始执行之前,还需要经过优化器的处理。

        优化器的作用是在表中有多个索引时,决定使用哪个索引;或者在一个语句中涉及多个表的关联(join)时,决定各个表的连接顺序。例如,当执行以下语句时:

select * from t1 join t2 using(ID) where t1.c=10 and t2.d=20;

        优化器可以选择两种不同的执行方法。第一种方法是先从表t1中选择满足条件c=10的记录的ID值,然后根据这些ID值与表t2进行关联,并判断t2中的d值是否等于20。第二种方法是先从表t2中选择满足条件d=20的记录的ID值,然后根据这些ID值与表t1进行关联,并判断t1中的c值是否等于10。

        虽然这两种执行方法的逻辑结果是一样的,但是它们的执行效率可能不同。优化器的作用就是决定选择使用哪种执行方法,以提高查询的效率。

5.执行器

        MySQL通过分析器确定要执行的操作,然后通过优化器确定如何执行操作,进入执行器阶段开始执行语句。

        在执行之前,执行器首先要判断用户对表T是否具有查询权限。如果没有权限,将返回相应的错误信息,例如:

mysql> select * from T where ID=10;
ERROR 1142 (42000): SELECT command denied to user 'b'@'localhost' for table 'T'

对于没有索引的表T,执行器的执行流程如下:

  1. 调用InnoDB引擎接口获取表的第一行数据,并判断其ID值是否为10。如果不是,则跳过该行;如果是,则将该行加入结果集。
  2. 调用引擎接口获取下一行数据,并重复相同的判断逻辑,直到获取到表的最后一行。
  3. 执行器将满足条件的所有行组成的结果集返回给客户端。

        对于有索引的表,执行逻辑类似。首次调用的是"获取满足条件的第一行"接口,然后循环调用"获取满足条件的下一行"接口。这些接口已经在引擎中定义好。

        在数据库的慢查询日志中,可以看到一个名为"rows_examined"的字段,表示执行过程中扫描了多少行。这个值是在执行器每次调用引擎获取数据行时累加的。需要注意的是,在某些情况下,执行器调用一次接口,引擎内部可能会扫描多行数据,因此引擎扫描的行数与"rows_examined"可能不完全一致。

        关于一条查询语句的执行流程大致介绍到这里,本人只是个MySQL学习者,以上是本人通过阅读极客时间的《MySQL45讲》总结出的读书笔记,如有错误,请在评论区回复或私信作者。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值