由于mysql在实现时和redis一样,采用的也是C/S架构,所以想要执行一个select语句首先要把语句从客户端发送到服务器,但是不可能任何一个客户端想和服务器建立连接都会被允许,所以就需要一个组件来管理与客户端的连接,这个组件叫作连接器,那么连接器会做哪些事情呢?
首先连接器会负责建立客户端和服务器之间连接时服务器要做的部分,在建立连接成功后,连接器会验证客户端的身份,客户端在和服务器建立连接时会携带账号和密码,如果客户端向服务器发送的账号和密码与服务器设置的账号和密码不一致,服务器就会向客户端返回一个”Access denied for user”的错误,如果身份验证通过,连接器就会到权限表中查出这个账号具有的权限,在我们执行某个语句之前,会先验证账号是否有权限执行这个语句,也就是说比较执行该语句所需要的权限和账号具有的权限,只有在账户具有的权限高于需要的权限时,才会去执行这个语句。
那么这个时候就可能会出现这么一种情况,在连接建立后,权限表也查过了,这个时候用管理员账号更改了该账号的权限,那么此时再验证权限,比较的是原来的权限还是更改后的权限呢?比较的还是原来的权限。
建立连接,验证完权限后,连接就创建成功了,如果在某个时刻没有通过这个连接向服务器发送语句,那么这个连接就会进入”空闲”状态,连接连续处于”空闲”状态的时间不能太长,默认是8小时,超过这个时间连接就会自动断开。
如果在连接断开之后,客户端再次通过这个连接向服务器发送语句,就会收到lost connection to mysql的出错提醒,这个时候需要手动和服务器重连,并且重新发送语句。
Mysql建立的连接分为两种,一种是长连接,另一种是短连接,当我们建立的是长连接时,对于一个客户端,只要没有发生超时导致自动断开连接,那么这个客户端的语句都会通过这个连接发送到服务器,短连接则是即使没有超时,但是在发送几次语句后就会自动断开连接,再需要发送语句到服务器就会重新建立连接。
由于建立连接的过程需要经过三次握手,这个过程会比较耗时,反复建立连接会降低Mysql的使用效率,所以在创建连接时最好创建的都是长连接。那么怎么实现创建的连接都是长连接呢?但是创建的都是长连接也是有缺点的,因为在执行语句时使用的临时内存会绑定在连接对象上,只有在连接断开时才会释放这些内存,当长连接使用时间过长时,很容易造成可用的内存空间不足,进而导致mysql异常重启。
那么怎么解决这个问题呢?有两个方法,第一个方法就是每隔一段时间断开一次长连接,定期释放长连接占用的内存空间,第二个方法则是与Mysql的版本有关,只适用于Mysql5.7及之后的版本,新版本的做法是我们在执行一次会占用很大临时内存的语句后就重新初始化连接对象,重新初始化连接对象的意思是什么?重新初始化连接对象的意思是把连接对象中的所有字段都重新设置为初始值,这么做的好处是什么呢?好处在于不需要重新建立连接,也不需要重新进行权限验证,并且能够回收上一次执行语句时所占用的临时内存。
在建立连接之后,客户端就会把语句发送给Mysql服务器,服务器在接收到查询语句后,会先到查询缓存中找以前有没有执行过这个语句,如果以前执行过这个语句,就会把查询语句和查询结果以键值对的形式保存在查询缓存中,如果在查询缓存中能够找到这个语句,那么就会把查询结果直接返回给客户端,如果没有找到这个语句,就会继续执行接下来的阶段,并且会把查询出的结果保存在查询缓存中。
查询缓存的优点在于当缓存命中时,能够节省很多的时间,那么查询缓存有缺点吗?查询缓存的缺点在于它会经常失效,只要在某一张表上执行了更新语句,那么这张表上的所有查询缓存都会失效,所以说对于经常更新数据的数据库来说,查询缓存的命令率非常低,只有在静态表上,或者是在很久才更新一次的表上,使用查询缓存才利大于弊。
在Mysql8.0中,已经完全删除了查询缓存功能。
在没有命中查询缓存之后,Mysql会开始解析接收到的sql语句,解析sql语句的过程分为两个阶段,分别是”词法分析”阶段和”语法分析”阶段,。。。,解析sql语句的阶段通常被称作分析器阶段。
在解析完语句后,Mysql会评估不同执行方案的效率,评估不同执行方案的效率并且决定使用哪一个方案的阶段通常被称作优化器阶段。
接下来就是按照优化器阶段决定的方案具体执行,因此这个阶段被称作执行器阶段,在执行器阶段的开始,会先去判断当前账号是否有查询该表的权限,如果没有,就会向客户端返回没有权限的错误,这个时候就会出现一个bug,在查询缓存阶段我们并没有提到权限验证的操作,那这样不就会出现没有权限的账户查询到了相应的结果吗?即使这种情况发生的概率很低,但仍然是不合理的,Mysql对这种情况肯定有相应的处理,在命中缓存后返回查询的结果之前会进行权限验证。
如果有权限,Mysql就会根据表的定义中的引擎名称,使用该引擎提供的接口从表中查找数据。对于没有索引的字段的语句,会先调用”取表的第一行”这个接口,如果不满足语句中的条件,就跳过这行数据,如果满足就把这行数据放到结果集中,然后会重复调用”取表的下一行”这个接口,把满足语句条件的数据行放到结果集中,直到表的最后一行,为什么到最后一行就停止调用这个接口了?因为表的最后一行没有下一行了,然后把最终的结果集返回到客户端。
如果是对于有索引的字段的语句呢?具体执行过程是什么样的呢?区别在于第一次调用的是”取表中满足条件的第一行”接口,然后重复调用的是”取表中满足条件的下一行”接口,也就是说重复调用这个接口到下一个数据行行不满足条件时为止。这些接口都是存储引擎自己定义的,Mysql在执行器阶段只需要直接调用就可以了。