MySQL执行一条插入语句或者查询语句,实际上会经过哪些流程和部件,MySQL的架构是怎么样的,本文就一起从一条查询语句的执行流程开始来揭开面纱。
如以下的执行语句:
select * from test where a=1;
从我们初步使用sql我们知道,首先我们需要连接上mysql server,然后需要拥有对于表的查询权限,再然后是对查询语句做分析查询对应表的数据,返回结果,这在mysql中对应着几个特定的功能模块。
一、逻辑架构
MySQL Server逻辑架构如下图所示,分为连接器、查询缓存、分析器、优化器、执行器和存储引擎。
二、各组件功能
1.1 连接器
管理客户端的连接,进行相关的权限验证。这是数据库查询的第一步,当你输入以下命令尝试尝试连接数据库的时候就是会与连接器打交道,连接器在建立连接以后会查询权限表获得用户的相关权限,并且将此连接对应的权限缓存记录起来,后续这个mysql连接的操作都依赖于此时的权限,在建立连接以后即便重新修改权限,对于此连接也不会生效。
mysql -h$host -P$port -u$user -p
当连接完成以后,可以通过以下命令查看连接的状态:
show processlist;
客户端到server的连接如果一直没有请求,那么经历了一段时间以后连接会被关闭,连接被关闭以后如果客户端继续发起请求就会收到一个错误提醒: Lost connection to MySQL server during query。这个超时时间一般由参数wait_timeout指定,通过以下sql可以查询:
show variables like '%wait_timeout%';
一般来说数据库连接池组件都会有一些保活的机制,例如使用select 1语句定期探测。
MySQL中的连接分为长连接和短连接:长连接是指客户端的多次请求可以使用同一个连接,而短连接是每次请求后都断开连接,当下次请求来临又重新建立连接。短连接这种方式十分的消耗资源,一般建议使用长连接。
当然长连接的使用也会有些问题,MySQL执行过程中临时使用的内存是管理在连接对象里面的,当较长的时间连接不能释放的话,就会有造成OOM的可能。可以有两种解决方案:
1、MySQL5.7及以上版本,执行 mysql_reset_connection 来重新初始化连接资源。这个过程不需要重连和重新做权限验证,但是会将连接恢复到刚刚创建完时的状态。
2、定期断开长连接。一般来说数据库连接池都会有相关的机制配置,例如druid连接池maxAge的配置。
1.2 查询缓存
在MySQL中,每次查询语句的结果会被缓存,以key-value的形式存储,当相同的语句查询时就直接从缓存中获取响应数据返回,提升性能。
但是查询缓存有比较大的弊端,因为任何对于表的更新都会导致缓存失效,所以缓存命中率很低,只适合静态表数据或者更新情况非常少的数据,例如配置表。鉴于此情况,这个功能在MySQL8.0就被移除了,在此不再赘述。
1.3 分析器
分析器分为词法分析和语法分析,一条SQL语句首先需要进行词法分析,确定SQL的各个字段的含义,例如表名、字段名。完成词法分析以后就是进行语法分析,判断所写的语句是否符合MySQL的语法要求,如果不满足规范要求,会抛出以下错误信息:
You have an error in your SQL syntax
完成分析以后就会转入优化器环节处理。
1.4 优化器
一条语句执行过程中连接表的顺序,是否使用到索引,使用哪个索引,这些就是在优化器中决定的,优化器根据一定的规则确定一条语句实际的执行计划,生成执行计划以后通过执行器实际执行。
1.5 执行器
执行器作为Server层与存储引擎层的交互,它接收优化器优化后的实际执行语句,调用对应的存储引擎接口,获取返回的结果。在执行语句之前执行器会校验用户对于表的操作权限,如果符合才继续往下执行,为了获得某个结果集,执行器可能会多次的调用存储引擎的接口直到获取到所需要的结果集为止,在数据库的慢查询日志中可以看到一个 rows_examined 的字段,表示这个语句执行过程中扫描了多少行,这个值就是在执行器每次调用引擎获取数据行的时候累加的。
在使用explain语句查询sql的执行计划的时候也可以看到一个rows字段,也是类似的预估执行器在执行语句的过程中可能扫描的行数,只是这个数据只是一个预估并不准确。
注意,执行器调用一次,在存储引擎内部可能扫描了多行,因此引擎扫描行数跟 rows_examined 并不是完全相同的。
1.6 存储引擎
存储引擎是负责底层数据的存储,提供对外的读写接口,在MySQL中这是一个可插拔的设计,这可以说是MySQL流行的一个十分重要的原因。这种可插拔的设计使得My SQL支持多种存储引擎,可以适应不同的场景需要,例如默认的InnoDB,MyISAM和Memory等。