概述
我们学习东西,都不应该是先去了解细节,而是应该窥其全貌,这样才能从高纬度去理解问题,同样我们学习mysql也是一样的,我们应该先了解整个mysql架构,及来龙去脉,才能更好的掌握它。下面我们开始深入浅出的方式了解mysq基础架构知识。
SQL执行的来龙去脉
我们学习MySQL的时候,会编写SQL语句,如 select * from T where id=0这里查询T表,条件ID等于0。当我们执行这条SQL语句的时候,返回一个结果,却不知道这条SQL语句在MySQL里面的执行流程。如果我们深入去了解这个条SQL的执行过程,我们会发现MySQL在执行SQL过程中会经历非常多步骤,每一个步骤都有大量的功能支持,下面我们一一拆解这些功能,把它当成一辆完成的车一样,将零部件一件件拆解下来,深刻认识这些零件,让我们深入理解这些零件在MySQL所体现的作用。
SQL执行流程图
连接器
在使用MySQL的时候,用户会先对MySQL进行连接,在这时我们直面的第一个零件就是连接器,连接器负责和客户端建立连接,获取权限,维持和管理连接。连接命令 mysql -h ір − P ір -P ір−Pport -u$user -p执行完命令后,则建立连接,这个建立连接过程中会进行经典的TCP握手交互,之后认证身份,认证成功后会验证当前用户的权限,用于之后这个连接里面的权限判断逻辑,都会依赖此时读到的权限。
当我们建立连接后,我们可以使用show processlist 查看所有连接情况,当command 列显示为 “Sleep”时说明这个行记录是空闲连接。
如果当前连接的客户端太长时间没有活跃,连接器将会自动断开,这个时间,我们可以通过wait_timeout 控制,这个参数默认是8小时。
如果连接被断开之后,客户端再次发起请求连接,会收到一个错误提醒:Lost connection to MySQL server during query。如果这个时候你看到这个信息,想要继续操作,则需要重新连接,才能继续执行。长连接在数据库里面使用,长连接是指当客户端连接成功后,如果客户端有持续请求,则会一直使用这个连接。短连接在数据库使用,短连接是指客户端连接成功后,客户端使用一次这个连接后,这个连接就会关闭,如果下次需要连接则需要重新创建短连接,这个创建连接的成本是很高的,所以一般在数据库中建议使用长连接,避免频繁创建连接,浪费资源。当时使用长连接也会造成一些问题,如,如果大量连接创建后,我们会观察服务器内存,会发现内存占用较高,因为创建大量连接会导致系统内存占用过高,此时还可能经历被系统杀掉(OOM),从而出现MySQL服务重启的现象。
怎么解决长连接带来的问题呢,有两种方案如下?
● 定期断开长连接,避免大量无用连接而占用内存。在使用一段时间内,在程序里面判断一个占用内存的查询,断开连接,之后要查询在重新连接。
● 如果使用的MySQL5.7 或者比5.7更新的版本,可以在执行一次占用内存较大的操作后,通过执行mysql_reset_connection来重新初始化连接资源,这个过程不需要重连和重新做权限验证,但是这个操作会讲连接恢复到刚刚连接时的状态。
查询缓存(mysql8已经废弃)
建立连接后,开始执行SQL语句,执行逻辑会先查询缓存。MySQL拿到一个查询请求后, 会先到查询缓存看,之前是不是执行过这条语句。之前执行过的语句及其结果可能会以key-value对的形式, 被直接缓存在内存中。 key是查询的语句,value是查询的结果。如果你的查询能够直接在这个缓存中找到key, 那么这个value就会被直接返回给客户端。
但是大多数情况下我会建议你不要使用查询缓存,为什么呢?因为查询缓存往往弊大于利。
查询缓存的失效非常频繁, 只要有对一个表的更新,这个表上所有的查询缓存都会被清空。因此很可能你费劲地把结果存起来, 还没使用呢, 就被一个更新全清空了。对于更新压力大的数据库来说,查询缓存的命中率会非常低。除非你的业务就是有一张静态表,很长时间才会更新一次。
比如,一个系统配置表,那这张表上的查询才适合使用查询缓存。MySQL也提供了这种“按需使用”的方式。你可以将参数query_cache_type设置成 DEMAND,这样对于默认的SQL语句都不使用查询缓存。而对于你确定要使用查询缓存的语句,可以用SQL_CACHE显式指定,像下面这个语句一样:select SQL_CACHE * from T where ID=10;
MySQL 8.0版本直接将查询缓存的整块功能删掉了, 8.0开始彻底没有这个功能了。
分析器
如果没有命中缓存,则会进行执行SQL环节,在到真正执行SQL语句前,会进行SQL语句分析,然后对SQL语句的解析。而分析器又被称为“词法分析器”,你输入的是由多个字符串和空格组成的一条SQL语句,MySQL需要识
别出里面的字符串分别是什么,代表什么。做完了这些识别以后, 就要做“语法分析”。根据词法分析的结果, 语法分析器会根据语法规则,判断你输入的这个SQL语句是否满足MySQL语法。
优化器
经过了分析器, MySQL就知道你要做什么了。 在开始执行之前,还要先经过优化器的处理。优化器是在表里面有多个索引的时候,决定使用哪个索引,或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序。
执行器
开始执行的时候, 要先判断一下你对这个表T有没有执行查询的权限,如果没有,就会返回没有权限的错误,执行器调用一次。 如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引
擎提供的接口,在引擎内部则扫描了多行, 因此引擎扫描行数跟rows_examined并不是完全相同的。