MySQL基础架构(一条语句如何查询)
MySQL的内部组件
这篇文章主要是来聊一下MySQL的基础架构。在工作中我发现了一个问题,许多小伙伴虽然已经用了许久的MySQL数据库来处理业务,熟练的使用CRUD并且能针对索引内存做一定的优化,但是对MySQL内部架构缺乏了解,但是如果能知道MySQL的各个组件以及相应的组件处理什么逻辑,对于MySQL的使用是有很大的帮助的。
总的来讲,MySQL内部大致可以分为七个组件:
客户端 连接器 查询缓存 分析器 优化器 执行器 存储引擎
如上图,每个组件在MySQL内部分别做了不同的事情。而存储引擎(InoDB,MyISAM等)是通过插件模式接入MySQL的server层的(只要是实现了MySQLserver层数据读写接口的存储引擎都可以像USB接入电脑一样接入MySQL使用)
我们来看看这些组件在一次sql执行过程中,到底都做了一些什么。
连接器
MySQL的连接器负责server端与客户端建立连接,在客户端输入:
mysql -h$ip -P$port -u$user -p
当连接成功之后,首先,连接器会验证输入的账号密码是否正确,当用户密码验证通过之后,连接器会在权限表中查询出该用户拥有的权限,之后该用户所有的操作都会基于这个权限来判断。所以,一个用户连接建立成功了之后,即使修改了该用户的权限,也不会影响到这一次连接的权限。
每个客户端建立连接之后,就会有一个新的连接,通过命令:show processlist 可以查看到当前的所有连接。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CPGNfc7E-1572790104798)(en-resource://database/402:0)]
如果当前客户端没有进行任何CRDU操作,则在Command参数中可以看到当前的进程状态为sleep。如果客户端长时间没有操作,则server端会主动断开连接。这个时间参数是wait_timeout控制的,默认是8小时。
查询缓存
在MySQL的select语句执行之后,执行逻辑就来到了第二步:查询缓存。MySQL的查询并不会直接读写硬盘,只有在缓存中没有的情况下才会直接读硬盘。
在mysql的缓存没有消耗完毕之前,所有之前执行的语句和相应的结果会以key-value的形式被直接存在缓存池(内存)中。如果你的查询语句匹配到到了一个key,则直接返回给你缓存中的value结果集。这样就避免了对硬盘的读写,所以在业务中的热数据(查询次数很平凡的sql语句)的查询速度会非常快。
所以,在MySQL的查询中,如果可以命中缓存就不需要执行后面的复杂操作直接返回,效率会十分高。平时监控一下hit rate(缓存命中率)的值也是很有必要的。
另外,在当前普遍的MySQL服务器中,索引的非叶子页基本都存储在查询缓存中,在并非是热点数据的查询中,只要用到了正确的索引,那么只需要最后在查询叶子页的数据时才需要读一次磁盘。
虽然看上去MySQL的查询缓存看上去能很强,但是我们却不能过分的依赖缓存,因为MySQL的缓存失效非常频繁,而且只要对一个表有更新,表上的查询缓存就会被清空。所以还是要很好的设计查询的索引和其他相应的优化。
** 需要注意的是在MySQL8.0的更新中,MySQL将查询缓存功能删除掉了。
分析器
当查询没有命中缓存的时候,就走到了正常执行语句的流程。分析器会做“词法分析”。分析你输入的sql语句是否正确,并且分别代表了什么。如果你的语法出现了错误,就会报出错误。
优化器
分析器分析完了sql语句没有错误之后。在开始真正的执行sql之前,还需要经过优化器。
优化器是MySQL中很关键的一个组件,在一个查询之中优化器会决定使用哪一个索引,或者不使用索引做全表查询。
如果有的语句使用索引需要不断的回表查询(每次回表物化数据需要一次硬盘随机读),而全表查询的时间相应比较短(全表查询是硬盘顺序读),那么优化器可能会放弃索引而使用全表查询。
同时,如果一个查询有几个可能使用的索引,那么优化器会对这些索引的查询时间做一个预估,然后选择它觉得耗时最短的索引。
通过explain + sql语句可以直观的看到当前执行sql优化器对于索引的决策。经过了优化器之后,这个查询的执行决策就已经决定下来了。至于优化器如何抉择索引我会再开一篇文章讲解。
另外如果想深入了解优化器对于索引的决策,推荐一个本书《数据库索引设计与优化》。
执行器
执行器会根据当前表所存储的存储引擎,去调用相应引擎实的接。开始执行的时候,要先判断一下对这个表有没有执行查询的权限,如果没有,就会返回没有权限的错误。
至此,这个语句就执行完成了。
小结
至此MySQL的所有的组件都已经介绍完了,如果想要很好的使用MySQL,优化sql语句,我推荐了解一下MySQL的优化器,它与索引息息相关。