MySQL: 一条sql查询语句的执行流程

MySQL的基本架构图 :

MySQL: 一条sql查询语句的执行流程

        MySQL可以分为Server层和存储引擎层两部分。

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

        而存储引擎层负责数据的存储和提取。支持InnoDB、MyISAM、Memory等多个存储引擎。最常用的存储引擎是InnoDB,它从MySQL 5.5.5版本开始成为了默认存储引擎。也可以通过指定存储引擎的类型来选择别的引擎,比如在create table语句中使用engine=memory, 来指定使用内存引擎创建表。不同的存储引擎共用一个Server层

 

我们在数据库执行一条查询语句:

SELECT * FROM `user_info` WHERE id = 1;

第一步:连接器

首先,我们需要连接到数据库上,输入ip和端口后,然后可以在执行完命令后输入密码,连接上数据库;

mysql -h$ip -P$port -u$user -p

        连接成功之后,即使管理员修改了该用户的权限,也只能在下次连接中生效,不会影响已经打开的连接;如果客户端长时间没有请求,连接器就会自动断开,默认是8小时,这里可以通过wait_timeout参数控制

第二步:查询缓存

        连接建立完成后,会先到查询缓存看看,之前是不是执行过这条语句。之前执行过的语句及其结果可能会以key-value对的形式,被直接缓存在内存中。key是查询的语句,value是查询的结果。如果存在缓存就取缓存数据;没有查询到缓存,就会继续往下执行。

MySQL也提供了参数,可以按需来查询缓存,将参数query_cache_type设置成DEMAND,这样默认就是不查询缓存,在我们需要查询缓存是,在select后加一个参数SQL_CACHE,如下:

SELECT SQL_CACHE * FROM `user_info` WHERE id = 1;

        但是大多数情况下不建议查询缓存,因为缓存更新特别频繁,每次对表的更新都会刷新缓存,更新语句会把表上所有的缓存都清空,对于更新压力比较大的数据库,缓存命中率就会特别低。而且需要注意的是,MySQL 8.0版本直接将查询缓存的整块功能删掉了,也就是说8.0开始彻底没有这个功能了。

第三步:分析器

        分析查询语句是否符合SQL语法,会识别SELECT来判断是查询语句,识别user_info为表名,识别id为列名。如果不符合语法,MySQl会提示错误信息:

You have an error in your SQL syntax

第四步:优化器

        分析完成后,数据库就知道要做什么,接下来要处理怎么做的问题。优化器是在表中存在多个索引时,判断使用哪个索引进行查询;或者在多表联查时(join)决定各表的连接顺序等;优化器执行完以后,进行真正的执行操作;

第五步:执行器

MySQL分析出要怎么做之后,就会去打开表,打开表之前会再次进行权限校验,如果有权限则打开表

打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。

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

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

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

通过EXPLAIN也可以查询到最后查询遍历的多少行数据:

EXPLAIN SELECT * FROM `user_info` WHERE id = 1;

 结果可以看到扫描了多少行数据:

MySQL: 一条sql查询语句的执行流程