大家好,我是冰河~~

MySQL作为互联网行业应用最多的关系型数据库之一,与其收费、开源的个性是密不可分的。然而,很多小伙伴工作了很多年,只晓得应用MySQL进行CRUD操作,这也导致很多小伙伴工作多年后,想跳槽进入大厂,却在面试的时候每每碰壁。

问个简略的问题:select语句是如何在MySQL中执行的? 这也是很多面试官喜爱问的问题,如果你连这个简略的问题都不能答复的话,那就要好好布局下本人的职业生涯了。

好了,明天咱们就一起来聊聊select语句是如何在MySQL中执行的。文章的次要内容如下。

频繁应用的select语句

为了更好地贯通全文,这里先来列举一个最简略的select查问语句,例如:查问user表中id为1001的用户信息,应用上面的SQL语句进行查问。

select * from user where user_id = 1001;

当咱们在MySQL的命令行中输出上述SQL语句时,这条SQL语句到底在MySQL中是如何执行的呢?接下来,咱们就以这条SQL语句为例,说说select语句是如何在MySQL中执行的。

MySQL逻辑架构

在介绍select语句在MySQL中的执行流程之前,咱们先来看看MySQL的逻辑架构,因为任何SQL语句的执行都离不开MySQL逻辑架构的撑持。也就是说,SQL语句在MySQL中的执行流程与MySQL的逻辑架构是密不可分的。

在上图中,咱们简略的画了下MySQL的逻辑架构图,并且给出了逻辑分层和每层中各局部的性能。从逻辑上,咱们能够将MySQL粗略地分成三层:Server层、存储引擎层和系统文件层,而Server层中又能够分成网络连接层(连接器)和数据服务层(Server层)。

Server层中蕴含了连接器、查问缓存、分析器、优化器和执行器等MySQL的外围组成部分,另外,在Server层中还蕴含了所有的内置函数(比方:日期工夫函数、加解密函数、聚合函数、数学函数等),存储引擎、触发器、视图等等。

存储引擎层次要负责和系统文件层进行交互,存储引擎层自身是插件式的架构设计,反对InnoDB、MyISAM、Archive、Memory等存储引擎。在MySQL 5.5.5及当前的版本中,MySQL的默认存储引擎是InnoDB。

系统文件层次要负责存储理论的数据,将数据以文件的模式存储到服务器的磁盘上。

接下来,咱们就来说说一条select语句在MySQL的逻辑架构的每一部分到底是如何执行的。

连接器是如何受权的?

首先,咱们先来看看在服务器命令行输出连贯MySQL的命令时,MySQL的连接器是如何进行验证的。比方,咱们在服务器的命令行输出了如下命令。

mysql -ubinghe -p

执行“回车”后,输出binghe账户的明码,与MySQL进行连贯。此时,连贯的过程须要实现经典的TCP握手操作。之后,连接器就开始认证连贯的身份是否非法,最间接的就是验证用户名和明码是否正确。

如果用户名或者明码谬误,MySQL会提醒 Access denied for user 。如果用户名和明码正确,则连接器会到MySQL的权限表中查问以后连贯领有的权限。查问到权限之后,只有这个连贯没有断开,则这个连贯波及到的权限操作都会依赖此时查问到的权限。

换句话说,一个用户登录MySQL并胜利连贯MySQL后,哪怕是管理员对以后用户的权限进行了批改操作,此时只有这个用户没有断开MySQL的连贯,就不会受到治理批改权限的影响。管理员批改权限后,只有对新建的连贯起作用。

如果客户端连贯MySQL后,长时间没有执行任何操作,则连接器会主动断开与这个客户端的连贯。具体多长时间断开是由MySQL的参数wait_timeout管制的,这个值默认是8小时。咱们能够依据理论业务须要,自行调整这个参数的值,以使MySQL可能满足咱们的理论业务场景。

因为客户端与MySQL的连贯是比较复杂的,这个过程也是比拟耗时的,它会波及TCP的握手操作,还会查问以后连贯的权限信息等。往往在理论的工作过程中,咱们会应用数据库连接池的形式,将数据库的连贯缓存起来,这就意味着咱们是应用长连贯与MySQL进行交互的。

然而应用长连贯连贯MySQL也会有一个问题:那就是有时候会发现MySQL占用的内存涨得特地快,这是因为MySQL在执行的过程中,应用的长期内存是在连贯对象外面进行治理的。这些占用的资源只有在连贯断开的时候,才会被开释。如果连贯长时间不开释,就会呈现大量的长期内存占用内存空间。如果工夫久了,可能会导致占用过多的内存,从而被操作系统“毁灭”了,给人的感觉就是MySQL意外重启了。

咱们能够应用如下的计划来解决这个问题:

  • 定期或者执行过一个比拟占内存的查问操作后,断开连接,当前再从新建设和MySQL的连贯。
  • 如果应用MySQL 5.7或更新的MySQL版本,能够通过执行mysql_reset_connection从新初始化MySQL的资源。从新初始化的过程不会从新连贯MySQL,也不会从新做权限的验证操作。

查问缓存的作用是什么?

登录MySQL后,客户端就会与MySQL建设连贯,此时执行select语句时,首先会到查问缓存中查问是否执行过以后select语句。如果之前执行过相应的select语句,则执行过的select语句和查问后果会以key-value的模式寄存在查问缓存中,其中,key是查问语句,value是查问的后果数据。

如果在查问缓存中没有找到相应的数据,则会继续执行后续的查问阶段。执行实现后,会将后果缓存到查问缓存中。后续的查问如果命中缓存,则间接返回查问缓存中的数据,性能还是挺高的。

然而,大多数时候我不太倡议小伙伴们开启查问缓存,为啥?起因很简略:查问缓存生效的频率是十分频繁的,只有对一个表进行更新操作,则这张表上所有的查问缓存都会被清空。 而且在MySQL 8.0中,间接删除了查问缓存的性能(冰河在看MySQL源码时,也证实了这一点)。

分析器对select语句做了什么?

分析器次要是对select语句进行 词法剖析和语法分析 操作。

如果select语句没有命中缓存,则首先会由分析器对其进行“词法剖析”操作,此时,MySQL会辨认select语句中的每个字符串代表什么含意。

例如,MySQL会通过"select"关键字辨认出这是一个查问语句,也会把"user"辨认为"数据表名user",把"id"辨认成"字段名id"。接下来,就要进行“语法分析了”,依据语法规定,判断select语句是否满足MySQL的语法。如果判断出输出的SQL语句不满足语法规定,则MySQL会提醒相应的错误信息。

优化器是如何优化select语句的?

对select语句进行了词法剖析和语法分析后,还要通过优化器的优化解决能力执行。比方,咱们的select语句中如果应用了多个索引,则优化器会决定应用哪个索引来查问数据;再比方,在select语句中,有多表关联的操作,优化器会决定各表的连贯程序,数据表的连贯程序不同,对于执行的效率会大不相同,优化器往往会抉择应用查问效率高的连贯程序。

如果select语句通过优化器的优化之后,就会进入执行阶段了。

执行器如何执行select语句?

进入执行阶段的select语句,首先,执行器会对以后连贯进行权限查看,最间接的形式就是查看以后连贯是否对数据表user具备查问权限。如果以后连贯对数据表user没有查问权限,就会返回没有权限的谬误。例如,会返回如下谬误。

ERROR 1142 (42000): SELECT command denied to user 'binghe'@'localhost' for table 'user'

如果以后连贯具备对数据表user的查问权限,则会继续执行。首先会进行关上数据表的操作,此时优化器会依据创立表时应用的存储引擎,应用相应存储引擎的接口执行查问操作。这里,咱们举一个例子:

假如,咱们在id字段上没有建设索引,执行器执行的流程大抵如下所示。

(1)通过存储引擎读取数据表user的第一行数据,判断以后行的id值是否等于1001,如果不等于1001,则持续读取下一行数据;如果等于1001,则将以后行放入后果集中。

(2)持续通过存储引擎读取下一行数据,执行与(1)雷同的逻辑判断,直到解决完user表中的所有数据。

(3)解决完所有的数据后,执行器就会将后果集中的数据返回给客户端。

如果在id字段上有索引的话,执行的整体逻辑与id字段上没有索引大体一致。

如果开启了慢查问的话,执行select语句时,会在慢查问日志中输入一个rows_examined字段,这个字段示意select语句在执行的过程中扫描了数据表中的多少行数据。不过在有些场景下,执行器调用一次,存储引擎外部会会扫描多行,这就导致存储引擎扫描的行数与rows_examined字段标识的行数并不完全相同。

好了,明天就到这儿吧,我是冰河,咱们下期见~~