共计 3619 个字符,预计需要花费 10 分钟才能阅读完成。
大家好,我是冰河~~
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 字段标识的行数并不完全相同。
好了,明天就到这儿吧,我是冰河,咱们下期见~~