SQL语句执行顺序及在MySQL架构上的执行过程

MySQL基础架构

它的架构可以在多种不同场景中应用并发挥良好作用。主要体现在存储引擎的架构上,插件式的存储引擎架构将查询处理和其他的系统任务以及数据的存储提取相分离.

image

  • 连接器:身份认证和权限相关(登录时)
  • 查询缓存:执行查询语句时,会先去查询缓存(8.0已移除,功能不实用)
  • 分析器:没有命中缓存的话,SQL语句就会经过分析器,分析器主要是分析你的SQL语句需要干嘛,然后检查语法是否正确
  • 优化器:按照MySQL任务最优的方案去执行
  • 执行器:执行语句,然后从存储引起返回数据

MySQL架构主要分为Server层和存储引擎层:

**Server层:**主要包括连接器、查询缓存、分析器、优化器、执行器等等,所有跨存储殷勤的功能都在这一层实现,比如存储过程、触发器、视图、函数等,还有一个通用的日志模块.

**存储引擎:**主要负责数据的存储和读取,采用可替换的插件式架构,支持InnoDB、MyISAM、Memory等多个存储引擎,其中InnoDB引擎有自有的日志模块redolog模块。现在最常用的存储引擎是InnoDB,它从MySQL 5.5开始被当做默认的存储引擎.

Server层基本介绍

1. 连接器

主要和身份认证、权限相关功能相关,类比一个级别很高的门卫

主要负责用户登录数据库、进行用户的身份认证,包括校验账户密码及权限等操作,如果用户账户密码通过,连接器会到权限列表中查询该用户的所有的权限,之后再这个连接里的权限逻辑判断都是会依赖此时读取的权限数据,也就是说,后续只要这个连接不断开,即使管理员修改了该用户的权限,该用户也是不受影响的.

2. 查询缓存(8.0后移除)

查询缓存主要用来缓存我们所执行的查询语句以及该语句的结果集.

连接建立后,执行查询语句时,会先查询缓存,MySQL会先校验这个SQL是否执行过,以key-value的形式缓存在内存中,key是查询预计,Value是结果集。如果缓存key被命中,就会直接将查询结果返回;如果没有命中,就会执行后序的操作,完成后也会把结果缓存起来,方便下一次调用。当然在真正执行缓存查询时,还是会校验用户权限和是否有该表的查询条件.

缓存实用性非常低,对于不经常更新的数据来说,才可以使用缓存. 这也是为什么8.0版本后删除了缓存,应用场景较少.

3. 分析器

MySQL没有命中缓存,就会进入到分析器,分析器主要是用来分析SQL语句用来干嘛的

分析器也会分为几步:

1) 词法分析

一条 SQL 语句由多个字符串组成。首先要提取关键字,例如SELECT、提出查询的表名、提出字段名、提出查询条件等等等。完成这些操作,会进入第二步分析

2) 语法分析

主要判断你输入的SQL语句是否正确,检查语法

完成这两步后,MySQL就准备开始执行了。但是如何执行,怎么执行才是最好的结果呢,这时进入优化器

4. 优化器

优化器的作用是它任务最优的执行方案执行,比如多个索引的时候该如何选择索引,多表查询时如何选择关联顺序等等.

5. 执行器

当选择了执行方案后,MySQL开始准备执行,在执行前会校验用户有没有权限,如果没有权限,就会返回错误信息,如果有权限,就会去调用引擎接口,返回接口执行的结果

SQL语句的执行过程

我们常见也是常写的SQL语句分为两种:一种是查询,一种是更新(增加、更新、删除)

查询语句
select * from student A where A.age='18' and A.name='张三';

结合上面,分析下这个语句的执行流程:

  • 先检查语句是否有权限,如果没有权限,直接返回错误信息;如果有权限,在8.0前会先查询缓存,以这条SQL语句为key,在内存中查询是否有缓存。如果有,则直接返回结果;没有,则执行下一步

  • 通过分析器进行词法分析。提取SQL语句的关键元素,比如查询select、表名student、需要查询的字段*、查询条件。然后判断这个SQL语句是否有语法错误

  • 通过优化器进行确定执行方案,对上面的例子,可以有两种执行方案:

    1. 先查询学生表中姓名为“张三”的学生,然后判断是否年龄是18

    2. 先找出学生中年龄18岁的学生,然后再查询姓名为“张三”的学生

    优化器会根据自己的优化算法去选择执行哪一个方案

  • 进行权限校验认证,如果没有权限则返回错误信息;如果有权限就会调用数据库引擎接口,返回引擎执行结果

更新语句
update student A set A.age='19' where A.name='张三';

接下来我们修改张三的年龄。其实这条语句基本也会沿着上述的查询流程走,只不过执行更新时需要记录日志。MySQL自带的日志模式binlog(归档日志),所有存储引擎都可以使用,InnoDB引擎自带一个redo log(重做日志)

那么我们就使用InnoDB引擎来分析下更新语句的流程:

  • 先查询到张三这个数据,如果有缓存,也是直接返回缓存
  • 然后拿到查询语句,把age改为19,然后调用引擎API接口,写入这一条数据。InnoDB引擎把数据保存在内存中,同时记录redo log,此时redo log进入prepare状态,然后告诉执行器,执行完成随时可提交
  • 执行器收到通知后记录binlog,然后调用引擎接口,提交redo log为提交状态
  • 更新完成

疑惑一:为什么需要使用两个日志模块,一个不可以嘛?

一个日志模块也是可以的。redo log日志是InnoDB引擎特有的,InnoDB引擎就是通过redo log来支持事务的。其他存储引擎是没有的,也就导致了其他引擎没有crash-safe的能力(即使数据库发生异常重启,之前的提交记录都不会丢失),binlog日志只能用来归档

疑惑二:两个日志模块,为什么要这么复杂,为什么redo log要引入prepare预提交状态?

假如(反证法)

  • **情况一:先写redo log直接提交,再写binlog。**写完redo log后,机器突然发生异常,binlog日志没有写入,那么重启后这台机器会通过redo log恢复数据,但是binglog并没有记录该数据,后续进行机器数据备份时,就会丢失这一数据,同时主从同步也会丢失
  • **情况二:先写binlog,再写redo log。**假设写了binlog,机器异常重启,由于没有redo log,本地无法恢复这一条记录,但是binlog上又有这条记录,就会产生数据不一致的情况

如果采用redo log两阶段提交的方式就不一样了。写完binlog后,再提交redo log就会防止出现上述问题,从而保证了数据一致性. MySQL处理流程如下:

判断redo log是否完整,如果判断完整,就立即提交;如果redo log只是预提交但不是commit状态,这个时候再去判断binlog是否完整,如果完整就提交redo log,否则进行回滚。这样就保证了数据一致性问题

总结
  1. MySQL主要分为Server层和引擎层,Server层主要包括连接器、查询缓存、分析器、优化器、执行器,同时还有一个日志模块(binlog),这个日志模块所有执行引起都有,redo log只有InnoDB有

  2. 引擎层是插件式的,目前主要包括:MyISAM、InnoDB等等

  3. 查询语句执行流程如下:权限校验 => 查询缓存 => 分析器 => 优化器 => 权限校验 => 执行器 => 存储引擎

  4. 更新语句执行流程如下:分析器 => 权限验证 => 执行器 => 存储引擎 => redo log(prepare状态) => binlog => redo log(commit状态)

SQL语句的执行顺序

image

猜你喜欢

转载自blog.csdn.net/weixin_44723496/article/details/113103928