各位客官,大家早上、中午、晚上好啊。今天,我们来讲讲MySQL的基础逻辑架构。
MySQL的架构分为Server层和存储引擎层,先来简单概括一下MySQL的两层架构——MySQL的Server层主要负责建立连接、分析和执行SQL语句,存储引擎层负责存储和读取数据。而我们本次的重点落在Server层,存储引擎层俺也不太会,就不献丑了,害怕说多错多。
Server层
MySQL的Server层主要分为连接器、查询缓存、解析器、预处理器、优化器和执行器,共"一查五器",此外所有的内置函数(日期、数学函数等)和所有跨存储引擎的功能也在Server层实现。接下来,我们依次来介绍Server层中每一个开发者会用到的"一查五器"。
连接器
我们在使用MySQL之前,肯定要先登录MySQL,连接到MySQL服务才能进行后续的相关操作,而建立连接的这个过程就是交由连接器来处理的。
mysql -uroot -p
-p之后输入密码之后,连接器就开始工作了。
首先,连接器和客户端之间会进行TCP三次握手(计算机网络的知识),因为MySQL是基于TCP协议进行数据传输的。
三次握手成功之后,连接器会开始验证我们的用户名和密码是否正确,若用户名或密码有误,会报错"Access denied for user",然后客户端连接失败。
如果用户名和密码都正确,连接器会获取当前登录用户的权限并保存起来,后续的一系列操作都会基于连接时保存的权限进行逻辑权限判断。
权限保存完毕之后,连接成功,连接器的任务完成可以下班了。
查询缓存
连接器下班了之后,客户端就可以向MySQL发送数据了。假设这时客户端向服务端发送了一个查询语句,这时又轮到哪个牛马该上班了呢?
MySQL接收到这个SQL语句之后,会解析出SQL语句的第一个字段,确定该SQL语句的类型。若是查询语句(select),MySQL就会先到查询缓存中查询是否有对应的缓存数据。查询缓存是以key-value的键值形式存储缓存的,key是SQL语句,value是SQL语句查询到的数据。若查询缓存中能够直接得到数据,则直接将缓存中的数据返回给客户端,查询结束。若查询缓存中没有对应缓存,则继续往后执行。
一说到缓存,我们很容易就想到redis,然后就会觉得这是一个很好的东西。但其实MySQL的查询缓存相当鸡肋,只有SQL语句一摸一样,才会命中缓存,缓存命中率极低。而且,一旦某个表进行了一个增删改的更新操作,该表的缓存会被立即清除。对于频繁更新的表来说,可能还没用到缓存中的数据呢,数据就被一波灭掉了,缓存了个寂寞。要知道,缓存数据这个操作也是需要消耗CPU资源的,频繁的增删缓存对MySQL的性能也会有影响。
因为查询缓存如此的不堪重用,在MySQL8.0之后,查询缓存就被开除了。那为什么我还要介绍呢?因为现在使用MySQL5.x版本的开发者不必MySQL8.0少,我们没法保证自己以后一定不会用到MySQL5.x;
解析器
当SQL语句来到解析器的时候,解析器的两位智囊就要开始上阵分析了。 解析器这个岗位上包括了两个部分,词法分析和语法分析。
词法分析
MySQL的词法解析器会将SQL语句的字段一个一个识别出来,识别它们都是什么,有代表什么。区分出什么是关键字,什么是非关键字。关键字就是select、where、from、>、<等这些,非关键字就是表名、字段名、常量等。
语法分析
接着语法解析器会根据词法解析器的分析结果和语法规则,检查我们的SQL语句是否有语法错误,如果没有语法错误就构建语法树,如果语法有误,则会报错。
语法树
语法树是在词法分析和语法分析都正确的基础上构建出来的,方便后续操作获取SQL类型、表名、字段名、where条件等。可以理解成,语法树是两位智囊分析后画出来的局势图。
值得注意的是检查判断SQL语句中的表存不存在,字段名存不存在的事情不是在解析器这的两位智囊来干的,而是在接下来的预处理阶段,由于都会报错,所以很多人误认为表不存在和字段不存在这个检查是在检查SQL语法是否有误的解析器阶段执行的,其实不是。
预处理器(prepare阶段)
预处理阶段,MySQL会做两件事,第一件事就是上面提到的,检查SQL语句中的表是否存在,字段是否存在。第二件事是将类似于select * from table这样的查询语句中的*换成该表中所有的字段,也就是扩展为表上的所有列,我们用 * 简化代表一个表中的所有字段,MySQL在查询之前会在预处理阶段帮我们还原出来。
优化器(optimize阶段)
经过预处理之后,我们还要为SQL语句指定一个执行方案,尤其是在一个表有多个索引(多个牛马),决定使用哪个索引(牛马);一个表与多个表关联(join)时,决定各个表之间的执行顺序。如果我们想要知道优化器选择了哪个什么执行方案,我们可以在执行语句之前使用explain来显示执行计划。
上图中的两个查询语句,从explain的结果中我们可以知道,第一个查询语句使用了全表扫描(type=ALL),第二个查询语句使用了主键索引(key=PRIMART、Extra=Using index)。
执行器(execute阶段)
MySQL通过解析器的智囊分析出SQL语句目的,通过优化器知道了该怎么做才能达到目的,最后由执行器(真正的天选打工人)来实现SQL的目的。
在开始执行SQL语句之前,MySQL会先进行权限校验(前面连接器时保存下来的权限),判断用户是否有执行相应操作的权限,若没有则返回没有权限的错误,有的话,就根据表的引擎定义,去调用对应存储引擎的api接口进行数据查询,与存储引擎层进行数据交互获取结果。
到这里,Server层就介绍结束了,简单总结一下。
连接器干了三件事,与客户端进行TCP三次握手、检查用户名和密码是否正确、保存登录用户的权限信息用于后续操作的权限判断。
查询缓存干了一件事,如果缓存命中则直接返回,没命中则继续向下执行,MySQL8.0已删除。
解析器干了三件事,词法分析、语法分析、构建语法树便于后续读取表名、字段名和SQL类型。
预处理器干了两件事,检查表名列名是否存在、将 * 扩展还原成表的所有字段。
优化器干了一件事,选出最佳的执行方案。
执行器干了两件事,检查权限和真正执行SQL。
"一查五器"的介绍到这里就结束了,接下来我们简单介绍一丢丢存储引擎层就下班跑路了。
存储引擎层
MySQL的存储引擎层位于服务器和文件系统之间,主要负责具体的表数据存储和管理。
主要的存储引擎及其特点
InnoDB
InnoDB支持事务(ACID)、支持行级锁、支持外键约束、使用B+树索引以及MVCC(多版本并发控制)
应用场景:需要事务处理的应用、需要高并发的应用、需要复杂查询和外键约束的应用
MyISAM
MyISAM不支持事务和外键约束,支持表级锁、使用B+树索引以及提供全文索引功能。
应用场景:需要快速读取的应用、不需要处理事务的应用、需要全文搜索的应用
MEMORY
MEMORY和MyISAM一样不支持事务和外键约束,MEMORY是将表数据存储在内存中的,同时支持哈希索引(InnoDB不支持哈希索引)。
应用场景:需要极快读写的临时表、需要高速缓存的应用。
最后
MySQL的基础逻辑架构到这里就算结束了。在这篇文章中,我只是简单的说了一下MySQL的架构里有什么东西,每一个东西都提了一嘴而已,没有往深里去说,因为我自己现在也只是学了个皮毛,我的功力感觉还深入不进去,哈哈哈哈哈哈。
感谢看完的大家,文章开头的那副图是我自己画的,第一次画,画了老半天呢,供大家参考哈。是时候开溜摸鱼了,拜拜。