1. MySQL基础架构

图片.png MySQL可以分为Server层和存储引擎层两部分,Server层包括连接器、查询缓存、分析器、优化器、执行器等,大多数核心功能以及所有的内置函数、所有的跨存储引擎的功能都在这一层实现。而存储引擎层负责数据的存储和提取,从MySQL5.5开始,InnoDB成为MySQL默认的存储引擎。不同的存储引擎共用一个Server层。

2. 连接器

执行以下命令和客户端进行连接:

  1. mysql -h -P -u -p
  2. # -h后面跟ip,-P后面跟端口号,-u后面跟用户名,-p后面跟密码,但是建议-p跟回车再输入密码。
  1. 用户名密码认证通过,连接器会到权限表中查出该账户拥有的权限。之后该连接上的所有操作都依赖于此时读到的权限。也就是说就算此时你用管理员账号对该账号权限做了修改也不会影响到这个连接,需要重新连接修改才会生效。<br />连接完成后,输入show processlist命令可以看到所有连接的状态,Sleep表示正处于空闲状态中。<br />数据库里面的长连接是指连接成功后,如果客户端持续有请求,则一直使用同一个连接。短链接则是指每次执行完很少的几次查询就断开连接,下次查询再重新建立一个。使用过程中尽量使用长连接,但是全部使用长连接会导致MySQL占用内存涨的特别快,因为MySQL再执行过程中临时使用的内存是管理连接在对象里面的,只有在连接断开的时候才会释放。所以长连接累积下来,可能会导致内存占用太大,被系统强行杀掉(OOM),从现象看就是MySQL异常重启了。<br />有两种解决方案:
  1. 定期断开长连接。
  2. MySQL5.7及以上支持执行mysql_reset_connection来重新初始化连接资源,仅仅是刷新,不会重连也不会重新做权限验证。

3. 查询缓存

从MySQL 8.0开始,这个功能就没有了。大体的流程图如下:
图片.png
就和业务中的查询缓存是一样的,如果能够有效命中缓存那自然是快很多,但是如果是这样:

  1. 第一条select语句查询成功写进缓存。
  2. 第二条update语句更新数据,接着删除缓存。
  3. 第三条select语句和第一条select语句一模一样,但是仍然不会命中缓存。

实际上只要有对该表的更新,该表上的所有查询缓存都会被清空。所以更新频繁的表缓存的命中率会很低,静态表就可以使用查询缓存。但是根据8.0删除该功能可以看出,官方是不推荐我们使用查询缓存的,不然也不会整个砍掉。8.0以前的库表可以设置参数query_cache_type为demand,这样默认的sql都不使用查询缓存,要使用的可以按照如下sql显示指定:

  1. select SQL_CHACHE * from T where id = 1;

4. 分析器

如果没有命中缓存,接下来就是分析器的工作了,它会先进行词法分析,会分析出来哪个是表名、列名等。然后做语法分析,会根据语法规则判断输入的SQL是否满足MySQL语法规范。如果语法不对,那么常见的”You have an error in your SQL syntax”报错就会找到你了。如果没问题,那MySQL就知道你要做CRUD中的哪一个操作、去哪个表查哪些字段了,接下来就是优化器的工作了。

5. 优化器

优化器主要干什么呢?例如当表中有多个索引的时候,决定使用哪一个索引;或者在一个语句有多表关联的时候,决定各个表的连接顺序。从中选出效率最高的执行步骤,这也正是优化所在。

6. 执行器

经过上述步骤之后,就要开始进行执行了。

  1. 先判断你对该表有没有执行查询的权限,若没有,则返回权限错误。
  2. 有权限,就打开表继续执行,打开表时,会根据表引擎定义,使用引擎提供的接口。
  3. 无索引则从表的第一行开始逐行判断是否满足条件,不满足则跳过,满足则加入到结果集中,然后对下一行进行相同操作。
  4. 有索引会调用“取满足条件的第一行”接口,然后调用取“满足条件的下一行”接口。

可以在数据库的慢查询日志中看到一个rows_examined的字段,表示语句在执行过程中扫描了多少行,该值就是执行器每次调用引擎获取数据行的时候累加得到的。
有些场景下,执行器调用一次,在引擎内部则扫描了多行,因此引擎扫描行数跟rows_examined并不完全相同。