Mysql的查询语句从开始到返回结果经历了什么

539 阅读7分钟

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

在我写了很多查询语句之后,都没关注过SELECT语句从开始查询到返回数据是怎么实现的。

我只关注查询的数据返回了,很少关注这个数据是怎么返回的。

比如mysql服务器地址,或者用户密码错误,比如写的sql语句语法错误,mysql是怎么判断出来的。

自以为是的认知是直接从一张表找到数据就返回了what???

直到最近我司需要做一个元数据管理系统,我猛然想到这个问题,如果select查询这个功能需要我来写,我会怎么写。

那么最好的办法就是去看看mysql官网是怎么实现的,直接把执行过程搬到元数据管理模块中来。

做任何需求先得自己独立思考,再去求证,那么自己先来思考下mysql这个查询的执行过程需要做什么?

  1. 验证我们查询的mysql地址和端口,用户名和密码这些连接信息是否正确。
  2. 如果正确,拿到客户端传给我们的查询语句,确认这个查询语句是否正确。
  3. 查询语句正确,是不是先判断查询的所有表存在不,再判断查询的字段正确不,再判断查询的条件正确不。字段需要结合查询的表判断正确性。
  4. 如果这个查询语句的表,字段,查询条件都正确,那么我们需要校验是不是按SELECT语句的规范写的,说白了就是查询语句的格式校验。

主要的执行步骤我想的就这些,能链接到数据库的服务器,查询语句格式没问题,查询的表和字段也没问题,那么就是去执行查询就好了。

去看看官方是怎么搞的...

当我们执行一条普通的select语句,一般会用连接池连上我们的mysql数据库。

连接池配置主要有ip地址,端口号(默认3306),用户名和密码等。

当连接信息正确,执行mysql语句去数据库查询满足sql语句的记录,在执行这个select语句的时候,mysql内部的执行流程大致如下:

image.png

  • 这个过程中连接器起到了上文我们自己分析的校验mysql链接信息的作用。词法分析器起到了上文我们分析的校验查询语句格式和语句是否正确的作用。执行器是去执行查询,那么我们自己分析少了词法优化器,没考虑到缓存

连接器

连接器验证mysql服务器的地址和端口是否正确,用户名是和密码是否正确,当前用户是否有查询权限。

如果这些都正确那么就能和mysql服务器建立连接,那么建立连接之后的这个连接需要怎么管理是个问题。

是当前用户查询完当前语句就释放连接,还是建立一个长连接维持连接查询的状态。

mysql的做法是在跟服务端建立连接。在完成TCP握手后,会维持一个长连接的状态,如果你就连上服务查询了一条查询语句就再也没有其他操作了,那么这个连接就处于空闲状态,可以用命令show processlist查看。

当然我们不能一直让这个空闲长连接一直占着资源不断开,那么我们可以设置一个参数值,来配置这个断开空闲连接的时间。

就像我们设置redis缓存过期时间一样,你一直用当前缓存那么缓存过期时间会一直刷新,但是你一旦不用当前缓存,到缓存过期时间我们缓存就过期了,那么同样的道理当我们空闲连接到我们配置的最大时间,连接就断开。

mysql官方的配置参数是wait_timeout,默认是8小时。

至此和mysql建立的连接就完成了并在断开连接之前的时间内能正常使用。断开咋办断开了需要再使用肯定是重新建立连接呀。

查缓存

我看到缓存第一印象是像redis这种nosql的缓存。

那么我想mysql对每条查询语句都会有个缓存,如果你每次查询的语句都一样,查询结果也一样,那么我就从mysql的缓存拿结果,不用去真正执行查询数据库的操作,关键是怎么判断查询的结果和缓存中的是一致的没有变呢?

mysql的做法是如果开启了查询缓存,会建一张类似于key-value的map结构的数据结构。

key是查询的语句,value是查询的结果,那么当查询语句来的时候,我们先到这个key-value的缓存中找结果,如果找到结果就直接返回。

我上面提到怎么保证我这个查询语句的key查询的结果和数据库查询的结果一致呢?

mysql的做法是只要你查询的表有更新操作那么这张表的所有缓存都清理掉,是不是可以这样理解,我key-value存的数据都和数据库数据一致的,因为缓存存在就表明,在建立缓存到这次查询的时间段内,数据库对应的表是没有更新过的,那么从缓存查询结果就和数据库查询的结果一致。

问题来了那么频繁更新的表开查询缓存就没有意义了,会频繁的删查询缓存,在一些不用更新的表静态数据表使用mysql的缓存效果更好。

当前我们需要缓存的话更多的是借助其他技术实现,比如redis缓存等。

在mysql8.0之后,mysql的这个查询缓存是被废弃的。缓存的知识就到次下面看分析器。

分析器

分析器好理解,就是分析你写的sql查询语句正确不。

会从语法和词法的角度去分析,要我想我先分析关键字是否正确,是否存在select,from等关键字。

整句分析我会把查询语句分成几段,从select到form是一段,form到where是一段,where之后是一段,分析整个语句是否存在问题。mysql肯定也有自己的分析逻辑,在此没有深入研究。

如果分析发现写的sql语句有问题会给提示报错信息,会提示错误信息的位置等。

分析器执行完就表明你写的查询语句基本没问题的是可以运行不报错的。

优化器

在我上文分析的过程中,我是没想到需要优化器的,我认为sql语句都正确了那么就是去执行查询的结果了,mysql在查询之前加了优化器。

优化器顾名思义就是优化我们写的sql语句的,比如如果有索引会判断走哪个索引,有表关联的话会判断先关联哪张表后关联哪张表等。就是把我们写的sql通过优化器的执行逻辑,优化一遍,但是执行结果不会变,优化后查询的效率(时间)会提高。

如果我们写的sql都是不用优化的那么我想mysql也不需要有优化器这一步,但是我们做不到哇....做不到哇...

优化器就是锦上添花的一步。下面看执行器。

执行器

执行器就是去执行我们写的sql语句了,是查询过程中最后一步了。

执行过程中会去表查询结果,mysql会在这一步判断用户对这张表有查询权限没,但是我在想这个判断对表有没有权限能不能提到分析器这一步,你都没权限查询,还走优化器执行器干什么。

执行器执行完之后会把结果集返回给客户端。至此整个查询过程结束。

到此对整个sql查询语句从查询开始到返回数据有了一个大概的认识,那么如果需要优化mysql的执行效率,不单单从执行器这一步分析也会考虑在整个执行过程中有哪些地方可以优化。。。

好了拜拜了祝大家国庆快乐........