当前位置: 首页 > 科技观察

一条SQL语句在MySQL中是如何执行的?

时间:2023-03-12 03:49:22 科技观察

前言最近开始学习mysql相关的知识。我根据自己学到的知识,按照自己的理解整理分享出来。本文将分析下一条sql语句在mysql中的执行过程,包括sql在mysql中的查询,内部流程是怎样的,sql语句的更新又是如何完成的。在分析之前,我先带大家看一下MySQL的基础架构。了解MySQL由哪些组件组成,这些组件的功能是什么,可以帮助我们理解和解决这些问题。一、Mysql架构分析下面是mysql的简要架构图:mysql主要分为服务器层和存储引擎层。服务器层主要包括连接器、查询缓存、分析器、优化器和执行器。功能都在这一层实现,如存储过程、触发器、视图、函数等,还有一个通用的日志模块,binglog日志模块。存储引擎:主要负责数据的存储和读取。采用可替换插件架构,支持InnoDB、MyISAM、Memory等多种存储引擎。InnoDB引擎有自己的日志模块redolog模块。InnoDB版本5.5.5用作默认引擎。connector主要负责用户登录数据库,用户认证,包括验证账号密码,权限等操作,如果用户账号密码已经通过,connector会在权限表中查询该用户的所有权限,以及那么在这个连接中权限的逻辑判断就会依赖于此时读取到的权限数据。也就是说,只要后面不断开连接,即使管理员修改了用户的权限,用户也不会受到影响。查询缓存连接建立后,执行查询语句时,会先查询缓存。mysql会先检查sql是否执行过,并以Key-Value的形式缓存在内存中。Key是查询估计,Value是结果集。如果缓存key被破解,直接返回给客户端。如果没有,则进行后续操作,完成后将结果缓存起来,方便下次调用。当然,在真正执行缓存查询的时候,还是会检查用户的权限,看是否有该表的查询条件。Mysql查询不建议使用缓存,因为对于频繁更新的数据,缓存的有效时间太短,往往效果不好。对于不经常更新的数据,还是可以使用缓存的,Mysql8.0发布后删除了缓存功能。官方也认为这个功能在实际应用场景中很少用到,所以直接删除了。Analyzermysql没有***缓存,然后会进入分析器,主要用来分析SQL语句是干什么用的,分析器也会分为几个步骤:第一步,词法分析,一条SQL一条语句由多个字符串组成。首先要提取关键字,比如select、要查询的表、字段名、查询条件等等。完成这些操作后,您将进入第二步。第二步,语法分析,主要是判断你输入的sql是否正确,是否符合mysql的语法。完成这两步后,mysql就可以开始执行了,但是怎么执行,怎么执行才是最好的结果呢?这时候优化器就需要发挥作用了。优化器优化器的作用是执行它认为是最好的执行计划(虽然有时不是最好的),比如有多个索引时如何选择索引,查询多张表时如何选择关联顺序,ETC。。执行者选择好执行计划后,mysql就准备开始执行了。首先,它会在执行前检查用户是否有权限。如果没有权限,将返回错误信息。如果有权限,就会调用引擎的接口。返回接口执行的结果。2.语句分析2.1查询语句上面说了这么多,一条sql语句是怎么执行的呢?其实我们的sql可以分为两种,一种是query,一种是update(add,update,delete)。我们先分析查询语句,语句如下:select*fromtb_studentAwhereA.age='18'andA.name='张三';结合上面的描述,我们分析这条语句的执行过程:首先检查语句是否有权限,如果没有权限,则直接返回错误信息。如果有权限,在mysql8.0之前的版本,会先查询缓存,以这条sql语句为key查询内存中是否有结果。如果有直接缓存,如果没有,执行下面的步骤。通过分析器进行词法分析,提取出sql语句的关键元素。比如上面的语句被提取为一个查询select,需要查询的表名为tb_student,需要查询所有的列。查询条件是这张表的id='1'。然后判断sql语句是否有语法错误,比如关键字是否正确等,如果检查没有问题,则进入下一步。下一步是优化器确定执行计划。上面的sql语句可以有两种执行计划:a.先查询学生表中名为“张三”的学生,然后判断年龄是否为18。先找出学生中18岁的学生,再查询名字为“张三”的学生。然后优化器根据自己的优化算法选择执行效率最高的方案(优化器认为有时候不一定是最好的)。然后确认执行计划后,就可以开始执行了。进行权限验证,如果没有权限,则返回错误信息,如果有权限,则调用数据库引擎接口,返回引擎的执行结果。2.2update语句以上就是一个查询sql的执行过程,那么我们来看看如何执行一个update语句呢?sql语句如下:updateb_studentAsetA.age='19'whereA.name='张三';让我们给张三,修改年龄。实际数据库中肯定不会设置年龄字段的,否则由技术负责人打字。其实第一条语句基本上会按照前面查询的流程,但是执行update的时候一定要记录log,这就会引入log模块。mysql自带的日志模块binlog(归档日志),所有的存储引擎都可以使用。我们常用的InnoDB引擎也自带日志模块redolog。我们将讨论这条语句在InnoDB模式下的执行过程。流程是这样的:先查询张三的数据,如果有缓存,也会使用缓存。然后获取查询语句,将age改为19,然后调用引擎API接口,写入这一行数据,InnoDB引擎将数据保存在内存中,同时记录redolog。此时redolog进入prepare状态,然后告诉execution,执行完成后可以随时提交。executor收到通知后记录binlog,然后调用engine接口,提交redolog作为提交状态。更新完成。这里肯定有同学会问,为什么要用两个日志模块,用一个日志模块不就行了吗?这是mysql以前的模型。MyISAM引擎没有redolog,所以我们知道它是不支持事务的,所以我们不是不能只用一个log模块,而是InnoDB引擎是通过redolog来支持事务的。那么,又有同学会问了,我用的是两个日志模块,总不能这么复杂吧,redolog为什么要引入preparepre-submit状态呢?这里我们用反证的方法来解释为什么要这样做?先写redolog直接提交,再写binlog,假设写完redolog后机器挂了,binlog日志没写,那么机器重启后,机器会通过redo恢复数据log,但是此时bingog并没有记录数据,后续机器备份的时候,这块数据就会丢失,同时主从同步也会丢失这块数据。先写入binlog,再写入redolog,假设写入binlog后,机器异常重启,由于没有redolog,机器无法恢复这条记录,但是binlog中还有一条记录,那么同理如上会出现数据不一致的情况。如果采用redolog两阶段提交方式,则方法不同。写完binglog,再提交redolog,就可以避免上述问题的发生,从而保证数据的一致性。那么问题来了,有没有极端的情况呢?假设redolog处于pre-commit状态,binglog已经写入,如果此时出现异常重启会怎样?这取决于mysql的处理机制,mysql的处理过程如下:判断redolog是否完整,如果判断完整,则立即提交。如果redolog只是预提交而没有commit,此时会判断binlog是否完整。如果完整则提交重做日志,如果不完整则回滚事务。这样就解决了数据一致性的问题。3.总结Mysql主要分为server层和engine层。服务器层主要包括连接器、查询缓存、分析器、优化器和执行器。还有一个日志模块(binlog)。这个日志模块可以被所有的执行引擎使用。共享。引擎层为插件式,目前主要包括MyISAM、InnoDB、Memory等。查询语句的执行过程如下:权限校验(如果安装了缓存)---》查询缓存---》分析器---》优化器---》权限校验---》执行器——》Engine更新语句执行流程如下:Analyzer----》PrivilegeCheck----》Executor---》Engine---redolog(preparestatus---》binlog---》redolog(commit地位)