本文章为 MySQL 学习笔记,参考极客时间《MySQL 实战 45 讲》

前言

mysql> select * from T where ID=10

当我们看到的只是输入一条语句,返回一个结果时,却不知道这条语句在 MySQL 内部的执行过程。
下面是 MySQL 的基本架构示意图,从中你可以清楚地看到 SQL 语句在 MySQL 的各个功能模块中的执行过程。
MySQL 实战 1.png
大体来说,MySQL 可以分为 Server 层和存储引擎层两部分。

Server 层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。

而存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持 InnoDB、MyISAM、Memory 等多个存储引擎。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始成为了默认存储引擎。

一、连接器

连接器负责跟客户端建立连接、获取权限、维持和管理连接。

建立连接的过程通常是比较复杂的,我们一般建议尽量使用长连接。但是使用长连接后,长期累积下来,可能导致内存占用太大,被系统强行杀掉,其实就是 MySQL 异常重启了。怎么解决这个问题呢?你可以考虑以下两种方案。

  1. 定期断开长连接。使用一段时间,或者程序里面判断执行过一个占用内存的大查询后,断开连接,之后要查询再重连。
  2. 如果你用的是 MySQL 5.7 或更新版本,可以在每次执行一个比较大的操作后,通过执行 mysql_reset_connection 来重新初始化连接资源。这个过程不需要重连和重新做权限验证,但是会将连接恢复到刚刚创建完时的状态。

二、查询缓存

连接建立完成后,你就可以执行 select 语句了。

MySQL 拿到一个查询请求后,会先到查询缓存看看,之前是不是执行过这条语句。如果你查询到在这个缓存中执行过,那么结果就会被直接返回给客户端。

但是大多数情况下我们不建议你使用查询缓存,因为查询缓存往往弊大于利。

查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会被清空。因此适用于更新频率较低的表。比如,一个系统配置表,那这张表上的查询才适合使用查询缓存。

需要注意的是,MySQL 8.0 版本直接将查询缓存的整块功能删掉了,也就是说 8.0 开始彻底没有这个功能了。那就更不建议使用了,哈哈。

三、分析器

如果没有命中查询缓存,就要开始真正执行语句了。

分析器会做两步操作:“词法分析”和“语法分析”,MySQL 需要识别出里面的字符串分别是什么,代表什么。如果你的语句语法不对,就会收到“You have an error in your SQL syntax”的错误提醒。

四、优化器

经过了分析器,在开始执行语句之前,还要先经过优化器的处理。

优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序。
举个例子:比如你执行下面这样的语句,这个语句是执行两个表的 join:

mysql> select * from t1 join t2 using(ID)  where t1.c=10 and t2.d=20;
  • 既可以先从表 t1 里面取出 c=10 的记录的 ID 值,再根据 ID 值关联到表 t2,再判断 t2 里面 d 的值是否等于 20。
  • 也可以先从表 t2 里面取出 d=20 的记录的 ID 值,再根据 ID 值关联到 t1,再判断 t1 里面 c 的值是否等于 10。

这两种执行方法的逻辑结果是一样的,但是执行的效率会有不同,而优化器的作用就是决定选择使用哪一个方案。

五、执行器

MySQL 经过了前几个阶段,进入了执行器阶段,开始执行语句。

开始执行的时候,要先判断一下你对这个表 T 有没有执行查询的权限,如果没有,就会返回没有权限的错误。如果有权限,就打开表继续执行。

执行流程是这样的,当执行查询语句时,如果没有索引,那么会一行一行的扫描,直到取到这个表的最后一行。如果有索引,执行的逻辑也差不多。第一次调用的是“取满足条件的第一行”的接口,之后循环取“满足条件的下一行”的接口,这些接口都是引擎中已经定义好的。


标题:(1)一条SQL查询语句是如何执行的——MySQL学习笔记
作者:AlgerFan
地址:https://www.algerfan.cn/articles/2019/08/06/1565052856889.html
版权声明:本文为博主原创文章,转载请附上博文链接!