陪你一起学mysql(三)-一条sql的前世今生

前言

我们时常调侃自己是 sql-boy,sql-girl,那 sql 语句是信手拈来,打开 navicat 就是一顿操作,输入,运行,结果就出来了。但是你知道,当我们输入一个 select 语句之后,在 MySQL 内部的执行过程吗?今天我们来科普下一条 sql 语句的前世今生!

Sql 语句执行流程图

sql 的一生

待分析的 sql:

select customer_id,first_name,last_name from customer where customer_id=14;

连接器

第一步,你会先连接到这个数据库上,这时候接待你的就是连接器。连接器负责跟客户端建立连接、获取权限、维持和管理连接。连接命令的写法:

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

输出命令,回车,接着输入密码就可以了。当然也可以直接在"-p"后面直接跟密码,但是这样容易造成密码泄露,生产环境严谨这样操作。经过经典的 TCP 握手,连接器就要开始认证你的用户名和密码,会有两种情况:

  1. 如果用户名或密码不对,你就会收到一个"Access denied for user"的错误,然后客户端程序结束执行。
  2. 如果用户名密码认证通过,连接器会到权限表里面查出你拥有的权限。之后,这个连接里面的权限判断逻辑,都将依赖于此时读到的权限。

注意:如果已经成功建立了连接,管理员又对该用户的权限进行了修改,此时已经建立的连接还是使用修改前的权限,只有再次重新建立连接,才会生效修改后的权限。

建立的连接可以使用如下命令进行查看:

show processlist

对于建立的连接如果没有其他操作,那被视为空闲连接,其中"command"字段此时的值为"sleep", 如果空闲的时间持续太长时间,那么连接就会被断开,这个时间是由参数"wait_timeout"来控制的,默认值是 8 小时。

查询缓存

第二步,建立完连接,就可以执行 select 查询操作了,此时要做的就是查询缓存

MySQL 拿到一个查询请求后,会先到查询缓存看看,之前是不是执行过这条语句。之前执行过的语句及其结果可能会以 key-value 对的形式,被直接缓存在内存中。key 是查询的语句 hash 之后的值,value 是查询的结果。

如果你的查询能够直接在这个缓存中找到 key,那么这个 value 就会被直接返回给客户端。

如果语句不在查询缓存中,就会继续后面的执行阶段。执行完成后,执行结果会被存入查询缓存中。你可以看到,如果查询命中缓存,MySQL 不需要执行后面的复杂操作,就可以直接返回结果,这个效率会很高。

查询缓存的设置如下:

show variables like 'query_cache_type';

默认是关闭的,因为不推荐使用查询缓存,因为查询缓存失效非常频繁,只要对一个表进行更新,那么和这个表相关联的所有的查询缓存都会被清空,这也就导致可能缓存成功了,还没使用呢,就被清空了,并且保存缓存也对mysql的读写会有一定的压力,所以总体来说,查询缓存是弊大于利的。mysql官方应该也意识到了,MySQL8.0版本直接将查询缓存的整块功能删掉了,也就是说8.0开始彻底没有这个功能了。

分析器

第三步,如果没有命中查询缓存,就要开始真正执行语句了。首先,MySQL 需要知道你要做什么,SQL语句是如何被识别的呢?因此需要对接收到 SQL 语句做解析。

这个阶段就是 MySQL 的 Parser 解析器和 Preprocessor预处理模块的功能,有以下三个过程:

1.词法分析

词法分析就是把一个完整的 SQL 语句分割成一个个的字符串,比如这条简单的SQL语句

select customer_id,first_name,last_name from customer where customer_id=14;

会被分割成10个字符串

select,customer_id,first_name,last_name,from,customer,where,customer_id,=,14

MySQL 同时需要识别出这个SQL语句中的字符串分别是什么,代表什么。MySQL 从"select"这个关键字识别出来,这是一个查询语句,把字符串“customer”识别成“表名 customer”,把字符串 “customer_id识别成“列 customer_id”。

2. 语法分析

语法分析器会根据语法规则做语法检查,判断你输入的这个sql语句是否满足MySQL语法。如果你的语句不对,就会收到“You have an error in your SQL syntax”的错误提醒,如果语法正确,就会根据MySQL定义的语法规则,根据sql语句生成一个数据结构,这个数据结构我们把它叫做解析树:

3.预处理

预处理器则会进一步去检查解析树是否合法,比如表名是否存在,语句中表的列是否存在等等,在这 一步MySQL会检验用户是否有表的操作权限。预处理之后会得到一个新的解析树。

优化器

第四步,查询优化器的作用就是根据解析树生成不同的执行计划,然后选择一种最优的执行计划,MySQL 里面使用的是基于成本模型的优化器,哪种执行计划执行时成本最小就用哪种。而且它是io_cost和cpu_cost的开销总和,它通常也是我们评价一个查询的执行效率的一个常用指标。

--查看上次查询成本开销show status like 'Last_query_cost';

优化器都做哪些优化处理呢:

  • 当有多个索引可用的时候,决定使用哪个索引
  • 在一个语句有多表关联(join)的时候,决定各个表的连接顺序,以哪个表为基准表
  • 其他的优化

执行器

第五步,MySQL 通过分析器知道了你要做什么,通过优化器知道了该怎么做,得到了一个查询计划。于是就进入了执行器阶段,开始执行语句。

  1. 开始执行的时候,要先判断一下你对这个表customer有没有执行查询的权限,如果没有,就会返回没有权限的错误
  2. 如果有权限,就使用指定的存储引擎打开表开始查询。执行器会根据表的引擎定义,去使用这个引擎提供的查询接口,提取数据

详细流程图

至此,这个语句就执行完成了,下面分享一张详细的流程图:

结束

此次分享的mysql就这么多了,需要交流学习可以关注公众号【温故知新之java】,互相学习,一起进步。

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章