天天看点

京东一面:说一下SQL查询语句的执行过程

作者:尚硅谷教育

我们在项目中避免不了要与数据库交互,那么一条SQL语句是如何执行的呢?这篇文章我们就来聊聊MySQL的基础架构。

一、MySQL 逻辑架构概览

在执行下面这个查询语句时:

select * from user where id = 10 ;

看到的只是输入一条SQL语句,返回一个结果,却不知道这条语句在MySQL内部的执行过程。

接下来就把MySQL拆解一下,让大家看看里面都有哪些“零件”。下面是MySQL的基本架构示意图:

京东一面:说一下SQL查询语句的执行过程

MySQL的逻辑架构图

总的来说,MySQL可以分为Server层和存储引擎两部分。

Server层:

Server层包括连接器、查询缓存、分析器、执行器等,包含了MySQL的大多数核心功能,还有内置函数(如日期、时间、数学和加密函数等)。

存储引擎层:

存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持MyISA、MInnoDB等多个存储引擎。现在最常用的是InnoDB,从MySQL5.5.5版本开始默认的存储引擎就是InnoDB。在执行create table建表的时候不指定引擎类型的话,默认使用的就是InnoDB。注意

注意:

在MySQL5.1及以前的版本,使用的默认存储引擎是MyISAM。

二、连接器

连接器一般会做两件事,一个是管理MySQL连接,一个是权限验证。下面来依次说明。

管理MySQL连接:

我们通常在连接MySQL服务器的时候要输入用户名和密码,如果是其他机器还需要输入指定的主机IP。连接命令:mysql -h ip -P port -u user -p

如果用户名和密码不正确,连接器就会返回错误信息“Access denied for user”。

权限验证:

如果用户名和密码认证通过了,连接器就会查询权限表里的权限。之后,这个连接里面的所有权限判断逻辑,都将依赖于此时读到的权限。

也就是说,当一个连接建立后,即使你在其他连接里修改了这个账户的权限,也不会对当前这个连接的权限造成任何影响。只有重新建立连接才会获取新的权限。

连接完成后,如果长时间没有操作,就会处于空闲状态。实际上对于一个MySQL连接来说,任意一时刻都有一个状态,可以使用“SHOW FULL PROCESSLIST”命令查看。如下图所示:

京东一面:说一下SQL查询语句的执行过程

Command 列就表示当前的状态。

客户端如果太长时间没有动静,连接器就会自动将它断开。这个时间是由参数 wait_timeout 控制的,默认值是8小时。可用命令查看:"show variables like 'wait_timeout';",如下图:

京东一面:说一下SQL查询语句的执行过程

三、查询缓存

连接建立完成后,就可以输入查询语句进行查询了。执行逻辑来到第二步:查询缓存。

1. 当MySQL拿到查询请求后,首先会到缓存中去看,之前是否执行过这条语句。如果当前查询正好命中查询缓存,那么缓存的值就会直接返回给客户端。

2. 如果语句不在缓存中,就会继续后面的执行阶段。执行完成后,执行结果会被存入查询缓存中。

3. 但是大多数情况下不建议使用查询缓存,因为既然涉及到缓存,就必然绕不开缓存一致性问题。

4. 值得庆幸的是,不需要我们进行额外操作,查询缓存并不会返回陈旧数据。当表被修改时,查询缓存中的任何相关条目都会被 flushed。

5. 对于MySQL8.0之前的版本,可以将参数“query_cache_type” 设置成 DEMAND,这样对于默认的 SQL 语句都不使用查询缓存。而对于你确定要使用查询缓存的语句,可以用 SQL_CACHE 显式指定,像下面这个语句一样:

mysql> select SQL_CACHE * from user where id = 1 ;

注意:

1.这里的 flushed 翻译为清空而不是刷新。

2.从 MySQL 5.7.20 开始,官方不再推荐使用查询缓存,并在 MySQL 8.0 中直接删除了查询缓存!

四、分析器

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

1. 分析器先会做“词法分析”,输入的SQL语句是多个字符串组成,MySQL需要识别里面的字符串分别是什么,代表什么。

2. 做完识别后紧接着就要做语法分析了。根据词法分析的结果,语法分析器会根据语法规则,判断这个SQL语句是否满足MySQL语法。

3. 分析器会根据SQL语句生成一个数据结构——解析树。如下图:

京东一面:说一下SQL查询语句的执行过程

注意:

如果语法不对,就会收到“You have an error in your SQL syntax”的错误提醒。

五、优化器

解析树是合法的,MySQL就知道了要干什么。但是一条SQL语句有很多种执行计划,最终的返回结果都相同。所以还需要优化器处理,选择那种执行计划。

优化器是在表里有多个索引的时候,决定使用哪个索引。或者说一个语句有多个表关联的时候,决定各个表的连接顺序。

举个例子:

select * from t1 where id = 10 and name = "good";

对于上面这个语句,可以先查找 name = good 在查找 id = 10 ,反之也行。但是这两种执行计划花费的时间成本是不一样的。

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

优化器阶段结束之后,这个语句的执行计划就确定下来了,就可以进入执行器阶段了。

六、执行器

MySQL 通过分析器知道了你要做什么,通过优化器知道了该怎么做,于是就进入了执行器阶段,开始执行语句。

1. 执行的时候和查询缓存的时候一样,在执行SQL语句之前会判断当前用户是否有权限操作这张表,如果没有,就会返回没有权限的错误。

2. 权限认证后MySQL会根据执行计划给出的指令逐步执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。

举例:

mysql> select * from user where id = 10;

假设这个例子的user表中,id字段没有索引,流程如下:

1.调用 InnoDB 引擎接口取这个表的第一行,判断 id 值是不是 10,如果不是则跳过,如果是则将这行存在结果集中。

2.调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。

3.执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。

至此,这个语句就执行完成了。

七、总结

至此关于SQL查询语句完整的执行流程的各个阶段介绍完了,基本的执行顺序就是“客户端->连接器->查询缓存->分析器->优化器->执行器”(MySQL8.0版本没有查询缓存)。优化器会改写SQL,包括join的连接顺序,匹配索引,确定最优的SQL执行策略。相信大家对SQL的执行过程也有了基本的认识,最后再回归一下流程图:

京东一面:说一下SQL查询语句的执行过程

继续阅读