一条sql查询是如何执行的?

参考:极客时间-MySQL实战45讲

环境:MySQL5.7 InnoDB 

 

一条语句的执行过程

 

     大体上,mysql可以分为server层与存储引擎层:

     server层包含连接器、查询缓存、分析器、优化器、执行器等,涵盖mysql的大多数核心服务功能,以及所有的内置函数(日期、时间、数学加密函数等)、所有跨存储引擎的功能(存储过程、触发器、视图等)

     存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持InnoDB、MyISAM、Memeory等,5.5.5版本开始模式为InnoDB

1.连接器

     负责跟客户端建立连接、获取权限、维持和管理连接

     连接命令一般是这么写的:     

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

     连接完成之后,如果没有后续动作,这个连接就处于空闲状态,你可以在show processlist命令中看到它,客户端如果长时间没动静,连接器救护自动将它断开,控制参数wait_timeout,默认8h

2.查询缓存

     mysql拿到一个查询请求后,会先查缓存,看之前是否执行过这条语句,以key-value形式存储,key是语句,value是结果,如果查询到,执行返回,效率极高

     查询缓存往往弊大于利,mysql8.0版本去掉了这个功能,对一个表的任何更新操作都会使缓存清空,因此对于更新压力大的数据库来说,查询缓存命中率极低,可参数控制是否开启

3.分析器

    如没命中查询缓存,就向下继续执行,分析器进行词法分析,若语法不对,客户端会受到"You have an error in you SQL syntax"的错误提示

4.优化器

    决定使用哪个索引、多表关联(join)、决定各表的连接顺序等由优化器决定

5.执行器

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

    先判断你对表T有没有执行查询的权限(注意在命中查询缓存的时候,会在返回缓存结果的时候,做权限验证,优化器也会在调用precheck权限验证),若有权限,打开表继续执行,打开表的时候,执行期会根据表的引擎定义,去使用这个引擎提供的接口。

    例:查询表T,ID字段没有索引,执行器的执行流程为:

select * from T where ID=10

    1.调用InnoDB引擎接口取这个表的第一行(我理解这里是在执行器中调引擎的接口,获取到数据后,放在server层),判断ID是不是10,如果不是则跳过,如果是则将这行存在结果集中;

    2.调用引擎接口取"下一行",重复相同的逻辑,直到取到这个表的最后一行;

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

    至此,这条查询语句就执行完了。

    对于有索引的表,执行逻辑也差不多,第一次调用的是“满足条件的第一行”这个接口,之后循环取“满足条件的下一行”这个接口,这些接口都是引擎中已经定义好的。

    你会在数据库的慢查询日志中看到一个row_examined的字段,表示整个语句中扫描了多少行,这个值就是在执行器每次调用引擎获取数据行的时候累加的。(注意:这个扫描的行数和引擎扫描的行数并不是完全相同的,因为执行器每调用一次,在引擎内部中可能扫描多行,后面章节会介绍引擎的内部机制)

小结:

    个人认为,理解sql的执行过程与内部机制对于问题排查与sql的优化十分重要,尤其是对于业务开发中表结构的确定十分重要,合适的索引设计可能会让你避免后期项目扩展时的数据库重构,相当于在mysql中选择一个扩展性好的设计模式。(我认为对于mysql内部机制的理解,InnoDB引擎更重要一些,因为mysql的这类数据库的性能瓶颈更多是在磁盘io上,因此了解InnoDB引擎在减少磁盘io这一块的设计思想更有利于我们设计高性能的索引结构)

posted @ 2021-04-02 15:07  叫我林大官人  阅读(59)  评论(0)    收藏  举报