深入了解mysql中sql查询语句是如何工作的?

写sql语句或许是很多后端程序员都需要做的事情,但是经常写sql语句的你知道一条sql查询语句是如何执行的吗?本篇文章带你一探究竟

首先带着问题去学习:下面的sql再简单不过了,执行完这条sql,你会得到一个结果。那么这个结果是如何产生的呢?

select * from T where id = 1;

先给大家看一张mysql基本的架构图

 

总体来说:mysql可以分为server层和存储引擎层

server层主要包含连接器,分析器,优化器,执行器等。跨存储引擎的功能都在server层实现,包括内置函数(时间,文本),触发器,存储过程,视图。

存储引擎层被mysql设计为可插拔式的,mysql5.5.5版本后默认使用InnoDB,因为InnoDB支持事务。还有其他类型比如MyISAM、Memory等。存储引擎层主要负责数据的读写。

图中很容易看到,存储引擎使用的是相同的server层。

第一步:连接器

毫无疑问,执行sql语句首先需要建立一个连接,这个时候连接器会等待你。连接器负责跟客户端建立连接、获取权限、维持和管理连接。

当你输入用户名,密码后,连接器会先验证用户名和密码是否正确。通过身份认证后,连接器还会去权限表中查询你的权限。言外之意,连接成功后的权限信息都依赖于连接器的这次查询,如果管理员修改了你的权限,在下次重新登录后才能生效。

需要注意的是,数据库的连接比较耗费性能,所以才有了许许多多数据库连接池的出现。

第二步:缓存查询

建立连接之后,mysql会拿到你的select语句,然后去查询缓存,查看一下之前是否执行过该语句。mysql的查询缓存会以key-value的形式存放在内存中。key是select语句,value是查询的结果集。如果找到相同的key就将结果直接返回,没有找到就进行下一步操作。

你会发现,在同一个连接中,执行相同的select,后来执行select的时间会比第一次查询的时间快很多,这就是缓存的作用。

需要注意的是:并不是任何时候都适合使用缓存。因为缓存会失效,一旦一张表中有新的数据变动,就会导致缓存失效。如果一张表更新的次数比查询的次数多,就不建议使用缓存。想象一下这种情况,你好不容易将数据缓存起来了,结果还没有使用就消失了,得不偿失。

MySQL提供了这种“按需使用”的方式。你可以将参数 query_cache_type 设置成 DEMAND,这样对于默认的 SQL 语句都不使用查询缓存。而对于你确定要使用查询缓存的语句,可以用 SQL_CACHE 显式指定,像下面这个语句一样:

select SQL_CACHE * from T where id = 1;

第三步:分析器

在第二步如果没有命中缓存,就会对select语句进行词法分析。分析器需要辨别T代表着查询的表,id代表查询的列。做完词法分析后会进行语法分析,主要是判断你输入的语句是否符合mysql的语法要求,如果不符合就直接报错。

第四步:优化器

优化器主要是对查询进行优化,比如索引的选择,表的关联顺序。优化器会判断如何更高效的执行语句。本篇文章暂时不涉及sql语句优化,下面文章会详细介绍。

第五步:执行器

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

执行语句的时候,会先判断一下你对查询的表T有没有执行查询的权限,如果没有,就会返回没有权限的错误。注意,在第二步查询缓存的时候,会在返回结果的时候做权限验证。

然后执行器就会调用存储引擎提供的接口进行语句查询。

针对刚开始写的select查询,执行器执行的步骤如下:

 

select * from T where id = 1;

假设id没有索引

1.调用引擎接口,找到对应的表,拿到该表的第一行数据,判断id是否等于1,不是则跳过,是则将数据存放在结果集中

2.继续扫描下一行,判断是否符合条件,直到将全表扫描完成。

3.将所有的结果返回给客户端。

假设id有索引

1.如果你大致了解索引的话,其实索引就相当于书本的目录,可以大大缩减查询的范围。如果有索引的话,首先会大致确定扫描的行数。

2.开始一行一行的扫描,寻找符合条件的数据。

3.将所有的结果返回给客户端。

在分析一条语句的时候,你可以使用explain进行解释,查看该语句扫描的行数。

 

 

结束了------------

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章