mysql转换为sql语句_转:⼀条sql语句在mysql中是如何执⾏
mysql视图和存储过程
前⾔
本篇⽂章分析SQL语句在MySQL中的执⾏流程,包括SQL的查询在MySQL内部会怎么流转,SQL语句的更新是怎么完成的。在分析之前我们⼀起看看MySQL的基础架构,知道了 MySQL由那些组件组成以及这些组件的作⽤是什么,可以帮助我们理解和解决这些问题。
MySQL架构分析
下⾯是MySQL的⼀个简要架构图:
MySQL主要分为Server层和存储引擎层
Server层
主要包括连接器、查询缓存、分析器、优化器、执⾏器等,所有跨存储引擎的功能都在这⼀层实现,⽐如存储过程、触发器、视图,函数等,还有⼀个通⽤的⽇志模块binglog⽇志模块。
存储引擎
主要负责数据的存储和读取,采⽤可以替换的插件式架构,⽀持InnoDB、MyISAM、Memory等多个存储引擎,其中InnoDB引擎有⾃有的⽇志模块redolog 模块,InnoDB 5.5.5版本作为默认引擎。
连接器
主要负责⽤户登录数据库,进⾏⽤户的⾝份认证,包括校验账户密码,权限等操作,如果⽤户账户密码已通过,连接器会到权限表中查询该⽤户的所有权限,之后在这个连接⾥的权限逻辑判断都是会依赖此时读取到的权限数据,也就是说,后续只要这个连接不断开,即时管理员修改了该⽤户的权限,该⽤户也是不受影响的。
查询缓存
连接建⽴后,执⾏查询语句的时候,会先查询缓存,MySQL会先校验这个SQL是否执⾏过,以Key-Value的形式缓存在内存中,Key是查询预计,Value是结果集。如果缓存key被命中,就会直接返回给客户端,如果没有命中,就会执⾏后续的操作,完成后也会把结果缓存起来,⽅便下⼀次调⽤。当然在真正执⾏缓存查询的时候还是会校验⽤户的权限,是否有该表的查询条件。
MySQL查询不建议使⽤缓存,因为对于经常更新的数据来说,缓存的有效时间太短了,往往带来的效果并不好,对于不经常更新的数据来说,使⽤缓存还是可以的,MySQL 8.0版本后删除了缓存的功能,官⽅也是认为该功能在实际的应⽤场景⽐较少,所以⼲脆直接删掉了。
分析器
MySQL没有命中缓存,那么就会进⼊分析器,分析器主要是⽤来分析SQL语句是来⼲嘛的,分析器也会分为⼏步:
第⼀步,词法分析,⼀条SQL语句有多个字符串组成,⾸先要提取关键字,⽐如select,提出查询的表,提出字段名,提出查询条件等。
第⼆步,语法分析,主要是判断你输⼊的SQL是否正确,是否符合MySQL的语法。
完成这2步之后,MySQL就准备开始执⾏,但是如何执⾏,怎么执⾏是最好的结果呢?这个时候就需要
优化器上场了。
优化器
优化器的作⽤就是它认为的最优的执⾏⽅案去执⾏(虽然有时候也不是最优),⽐如多个索引的时候该如何选择索引,多表查询的时候如何选择关联顺序等。
执⾏器
当选择了执⾏⽅案后,MySQL就准备开始执⾏了,⾸先执⾏前会校验该⽤户有没有权限,如果没有权限,就会返回错误信息,如果有权限,就会去调⽤引擎的接⼝,返回接⼝执⾏的结果。
语句分析
查询语句
说了以上这么多,那么究竟⼀条SQL语句是如何执⾏的呢?其实我们的sql可以分为两种,⼀种是查询,⼀种是更新(增加,更新,删除)。我们先分析下查询语句,语句如下:
select * from tb_student A where A.age='18' and A.name='张三';
结合上⾯的说明,我们分析下这个语句的执⾏流程:
先检查该语句是否有权限,如果没有权限,直接返回错误信息,如果有权限,在MySQL 8.0版本以前,会先查询缓存,以这条SQL语句为key在内存中查询是否有结果,如果有直接缓存,如果没有,执⾏下⼀步。
通过分析器进⾏词法分析,提取SQL语句的关键元素,⽐如提取上⾯这个语句是查询select,提取需要查询的表名为tb_student,需要查询所有的列,查询条件是这个表的id='1'。然后判断这个SQL语句是否有语法错误,⽐如关键词是否正确等,如果检查没问题就执⾏下⼀步。
接下来就是优化器进⾏确定执⾏⽅案,上⾯的SQL语句,可以有两种执⾏⽅案:
a.先查询学⽣表中姓名为“张三”的学⽣,然后判断是否年龄是18。
b.先出学⽣中年龄18岁的学⽣,然后再查询姓名为“张三”的学⽣。
复制代码
那么优化器根据⾃⼰的优化算法进⾏选择执⾏效率最好的⼀个⽅案(优化器认为,有时候不⼀定最好)。那么确认了执⾏计划后就准备开始执⾏了。
进⾏权限校验,如果没有权限就会返回错误信息,如果有权限就会调⽤数据库引擎接⼝,返回引擎的执⾏结果。
更新语句
以上就是⼀条查询SQL的执⾏流程,那么接下来我们看看⼀条更新语句如何执⾏的呢?SQL语句如下:
update tb_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 为提交状态。
更新完成。
这⾥肯定有⼈会问,为什么要⽤两个⽇志模块,⽤⼀个⽇志模块不⾏吗?这就是之前MySQL的模式了,MyISAM引擎是没有redo log的,那么我们知道它是不⽀持事务的,所以并不是说只⽤⼀个⽇志模块不可以,只是InnoDB引擎就是通过redo log来⽀持事务的。那么,⼜会有同学问,我⽤两个⽇志模块,但是不要这么复杂⾏不⾏,为什么redo log要引⼊prepare预提交状态?这⾥我们⽤反证法来说明下为什么要这么做?
先写redo log直接提交,然后写binlog,假设写完redo log后,机器挂了,binlog⽇志没有被写⼊,那么机器重启后,这台机器会通过redo log恢复数据,但是这个时候bingog并没有记录该数据,后续进⾏机器备份的时候,就会丢失这⼀条数据,同时主从同步也会丢失这⼀条数据。
先写binlog,然后写redo log,假设写完了binlog,机器异常重启了,由于没有redo log,本机是⽆法恢复这⼀条记录的,但是binlog⼜有记录,那么和上⾯同样的道理,就会产⽣数据不⼀致的情况。
如果采⽤redo log两阶段提交的⽅式就不⼀样了,写完binglog后,然后再提交redo log就会防⽌出现上述的问题,从⽽保证了数据的⼀致性。那么问题来了,有没有⼀个极端的情况呢?假设redo log 处于预提
交状态,binglog也已经写完了,这个时候发⽣了异常重启会怎么样呢? 这个就要依赖于MySQL的处理机制了,MySQL的处理过程如下:
判断redo log是否完整,如果判断是完整的,就⽴即提交。
如果redo log只是预提交但不是commit状态,这个时候就会去判断binlog是否完整,如果完整就提交redo log,不完整就回滚事务。
这样就解决了数据⼀致性的问题。
总结
MySQL主要分为Server层和引擎层,Server层主要包括连接器、查询缓存、分析器、优化器、执⾏器,同时还有⼀个⽇志模块(binlog),这个⽇志模块所有执⾏引擎都可以共⽤。
引擎层是插件式的,⽬前主要包括,MyISAM、InnoDB、Memory等。
查询语句的执⾏流程如下:权限校验(如果命中缓存)→查询缓存→分析器→优化器→权限校验→执⾏器→引擎
更新语句执⾏流程如下:分析器→权限校验→执⾏器→引擎→redo log(prepare 状态)→binlog→redo log(commit状态)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。