学习MySQL过程的笔记记录下来,方便后续自己查阅和复习;
【问题:select * from user where id = 1这条SQL语句在MySQL中是如何执行的呢】
这篇笔记能很好地的解答这个问题。我们将拆解MySQL中的各个部件,加深自己对MySQL的理解;
【答案:SQL语句经过连接器–>分析器–>优化器–>执行器–>存储引擎,获得查询结果】
1. MySQL基础架构
- MySQL的基本架构示例图如下所示(箭头表示SQL语句的执行过程):
- MySQL主要分为两个部分:Server层、存储引擎层;
- Server层: 包含组件有连接器、查询缓存、分析器、优化器、执行器等,涵盖MySQL的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有的跨存储引擎的功能在这实现,比如存储过程、触发器、视图等;
- 存储引擎:负责数据的储存和提取,架构模式是插件式,支持InnoDB、MyISAM、Memory等多个存储引擎(InnoDB最常见,已在mysql5.5.5版本之后成为默认引擎);
结合开头的查询语句,走一遍整个执行流程,依次看个每个组件的作用;
2. 连接器
第一步,需要先连接上这个数据库,这时会用到连接器;
- 连接器:负责与客户端建立连接、获取权限、维持和管理连接;
连接命令的语法一般如下所示:
mysql -h[MySQL服务器ip地址] -P[端口号] -u[用户名] -p[密码]
连接器连接过程:
- 通过ip地址和端口号进行经典的TCP连接;
- 验证数据库用户名和密码;
- 查询权限表查出当前用户的权限;
3. 查询缓存
第二步,连接建立完成后,就可以执行select语句了,执行逻辑会来到查询缓存这一步;
MySQL 拿到一个查询请求后,会先到查询缓存看看,之前是不是执行过这条语句。之前执行过的语句及其结果可能会以 key-value 对的形式,被直接缓存在内存中。key 是查询的语句,value 是查询的结果。如果你的查询能够直接在这个缓存中找到 key,那么这个 value 就会被直接返回给客户端。如果语句不在查询缓存中,就会继续后面的执行阶段。
需要注意的是,MySQL 8.0 版本直接将查询缓存的整块功能删掉了,也就是说 8.0 开始彻底没有这个功能了。
4. 分析器
第三步,对SQL语句进行解析,先做词法分析,再做语法分析;
- 词法分析:识别SQL语句中不同字符串代表的不同含义,这个查询语句中select识别为查询、user识别为表名、ID识别为字段名;
- 语法分析:这一步判断SQL语句是否满足MySQL的语法规范;
5. 优化器
第四步,在开始执行之前,优化MySQL的执行顺序(例如决定使用哪个索引,多表关联时,决定各个表的连接顺序);
例如,下面这个查询语句
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。
这两种执行方法的逻辑结果是一样的,但是执行的效率会有不同,而优化器的作用就是决定选择使用哪一个方案。
6. 执行器
第五步,进入执行器阶段,开始执行SQL语句;
开始执行的时候,要先判断一下你对这个表 T 有没有执行查询的权限,如果没有,就会返回没有权限的错误,(在工程实现上,如果命中查询缓存,会在查询缓存返回结果的时候,做权限验证。查询也会在优化器之前调用 precheck 验证权限)。
如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。
比如我们这个例子中的表 user 中,ID 字段没有索引,那么执行器的执行流程是这样的:
1. 调用 InnoDB 引擎接口取这个表的第一行,判断 ID 值是不是 10,如果不是则跳过,如果是则将这行存在结果集中;
2. 调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。
3. 执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。
如有索引,执行流程如下:
第一次调用的是“取满足条件的第一行”这个接口;
之后循环取“满足条件的下一行”这个接口(这些接口都是引擎中已经定义好的);
至此,这个语句就执行完成了。