一条普通的sql语句是如何执行的?
MySQL的内部架构及作用
今天开始是我们日志篇的内容啦,在正式开盘日志之前,需要先做个前提概要,就是搞明白一件事:MySQL是如何执行一条sql语句的。而弄清楚这个问题,就需要我们先理清楚MySQL的基础架构
基本的架构如下图, 下面以执行一条普通的select语句为例,盘一下每个组件的具体作用
从整体来说,MySQL可分为Server层和引擎层
Server层包括连接器,分析器,优化器,执行器,包含了MySQL大部分的功能。例如:所有的计算(函数,日期,时间等),存储过程,视图等。
引擎层负责数据的存和取,模式是插件式(可插拔,替换),有InnoDB, MyISAM等常见引擎。其中InnoDB为MySQL5.7版本后的默认引擎。
连接器
连接器主要负责管理连接,权限验证
无论是通过命令行窗口,Navicat,还是企业项目使用MySQL,第一步肯定是要和MySQL建立TCP连接,而这些连接工具对于MySQL来说都是客户端。连接的第一件事就是要在连接器这里做身份验证,如下:
mysql -h$host -P$port -u$user -p$pwd
如果密码错误,将会被拒绝连接;如果密码正确,连接器将会判断并保存登录的用户拥有的权限,之后执行任何操作(DML,DDL等)都会根据最初登录所获得的权限来做校验
登录成功后,通过 show processlist; 可看到当前客户端的连接数量
我在本地开启了两个客户端,如果连接建立后没做什么操作的话,连接就会变成Sleep(空闲)。如果太长时间没有动静的话,连接器就会主动将客户端关闭,由如下参数控制(默认是8小时):
查询缓存
缓存的作用是提升查询效率
当一条select语句进来时,会先去判断下是否有相关缓存,如果有的话,直接返回;没有的话才会去走分析器那一步。
但本质上这个功能很鸡肋,在MySQL5.7及之后的版本就已经被移除了,原因如下:
因此在大多数情况下,MySQL的缓存功能是弊大于利的, 因此后面也被移除掉了
分析器
分析器的主要作用:语义,语法分析
这时候才要开始真正执行的sql了,先交给分析器处理,让MySQL知道你想要做什么? 因此需要对sql进行预处理。比方说:
以及看这条sql是否符合MySQL的语法规范,有没有乱写。如下的例子:
前两条sql都是被分析器检测出查询的表、筛选的字段不存在被拦截
后一条sql则是不符合MySQL的语法规范,提示大家初学必会出现的经典的You hava an error ...
优化器
优化器的主要作用:生成这条sql具体的执行计划,优化方案
讲过了分析器,那MySQL就明白你要做什么了,下一步就要开始制定执行计划。就类似做产品一样,一开始总是要知道做它的目的(为什么要做),紧接着针对这个产品开始制定一系列的方针和计划。而sql就是我们的“产品”。
比方说,索引的选择,当关联的表比较多(需要决定表的连接顺序),以及表中的索引较多(确定走不走索引,走哪个索引合适?),选择比较多时,就需要优化器来做判断,而优化器所制定的“执行计划”,可以通过explain来查看,详细的explain分析可以参考(一)索引篇:详解MySQL索引的数据结构和类型
当有join时,优化器会自动判断小表,让小表作为驱动表,详细的分析过程可以参考我这篇博客里的:当索引碰到join时的分析。(二)索引篇:详解MySQL索引失效、索引实战及慢查询分析
当碰到多索引时,选哪个索引,以及走不走索引也是由优化器决定的。(后续会出相关的分析帖子哈哈!!)
优化器处理完后,sql具体的执行方案就定下来了,进入下一阶段!
执行器
执行器的主要作用:去操作引擎拿数据,并带回数据
当优化器告诉了MySQL要做什么,分析器告诉了要怎么去做,这时候就需要有一个执行者来行动了。
这时候,执行器的操作顺序大致如下:
最后,将符合条件的结果集再打包处理,返回给客户端,这条sql就处理完成了!
日志在MySQL中起到什么作用?
对于查询操作来说,查询总是幂等的(如果没有增删改操作,执行多少次查询结果都是一样的)。因此,我们也不必去考虑查询时,碰到的各种突发情况(断电,宕机,并发等等),会影响到数据的一致性。对于增,删,改操作就不一样了!
执行增删改的sql,肯定也是要走 连接器->分析器->优化器->执行器 的流程。除此之外,还需要做一些安全性措施(防止出现什么意外情况,数据不会丢失,错乱)。这时候,我们的日志就要登场啦!执行一条增删改语句时,还会同时写几个日志!(MySQL三大日志,binlog;redo log;undo log悉数登场)
binlog是干什么用的?
binlog的主要作用是:主从复制,归档备份。
写的时机:当MySQL执行完一条增删改sql后,执行器会将该sql写到binlog中。
使用MySQL肯定不会对主从复制感到陌生。而从库的数据从哪里来呢?
当主库执行增删改语句时,会将语句“写”在binlog日志里面,然后将binlog同步到从库上,从库直接执行就完事了!
undo log是干什么用的?
undo log的主要作用体现在两个地方,1:MVCC;2:事务的原子性
写的时机:当MySQL执行完一条增删改sql时,执行器会调用innoDB引擎的接口将sql的反义写到undo log中。(一条insert对应delete;一条delete对应insert;一条update new 对应update old;便于回滚)
MySQL的快照读是通过MVCC来解决事务的并发问题的,那历史版本记录放在哪里呢?就放在undo log里面
事务的原子性保证一个事务内的所有操作要么都成功,要么都失败。如果成功一半,失败了,就要通过undo log日志来回滚
事务和MVCC的具体分析可以参考这篇博客详解MySQL的事务和MVCC工作机制
redo log是干什么用的?
redo log的主要作用:保证数据不丢失,具备crash-safe能力(InnoDB引擎独有)
写的时机:当MySQL执行完一条增删改sql时,**执行器会调用innoDB引擎的接口将sql写到redo log中。
如果因为突发情况而导致丢数据,那这是很危险的事情了。redo log的存在即保证了数据的不丢失,具体的原理我们会在稍后展开。
如果将redo log, undo log, binlog都结合到MySQL的架构,则执行一条增删改语句时,执行流程如下图:
未完待续~~~ 后面会详细剖析每种日志的作用!