MySQL 是一个关系型数据库管理系统,在互联网企业中非常广泛的被使用。本文从一条查询sql入手,探索MySQL的执行过程
我们先来看下mysql的存储架构

MySQL 从概念上分为四层,这四层自顶向下分别是网络连接层,服务层(核心层),存储引擎层,系统文件层。我们自顶向下开始讲解。
网络连接层
主要负责连接管理、授权认证、安全等等。每个客户端连接都对应着服务器上的一个线程。服务器上维护了一个线程池,避免为每个连接都创建销毁一个线程。当客户端连接到 MySQL 服务器时,服务器对其进行认证。可以通过用户名与密码认证,也可以通过 SSL 证书进行认证。登录认证后,服务器还会验证客户端是否有执行某个查询的操作权限。这一层并不是 MySQL 所特有的技术。
服务层
第二层服务层是 MySQL 的核心,MySQL 的核心服务层都在这一层,查询解析,SQL 执行计划分析,SQL 执行计划优化,查询缓存。以及跨存储引擎的功能都在这一层实现:存储过程,触发器,视图等。
连接池(Connection Pool):管理、缓冲用户的连接,线程处理等需要缓存的需求
管理服务和工具组件(Services & utilities):系统管理和控制工具,例如备份恢复、MySQL 复制、集群等
SQL 接口(SQL Interface):接受用户的 SQL 命令,并且返回用户需要查询的结果
查询解析器(Parser):SQL 命令传递到解析器的时候会被解析器验证和解析(权限、语法结构)
查询优化器(Optimizer):SQL 语句在查询之前会使用查询优化器对查询进行优化
缓存(Caches):如果查询缓存有命中的查询结果,查询语句就可以直接去查询缓存中取数据
存储引擎层
负责 MySQL 中数据的存储与提取。 服务器中的查询执行引擎通过 API 与存储引擎进行通信,通过接口屏蔽了不同存储引擎之间的差异。MySQL 采用插件式的存储引擎。MySQL 为我们提供了许多存储引擎,每种存储引擎有不同的特点。我们可以根据不同的业务特点,选择最适合的存储引擎。
系统文件层
系统文件层主要包括MySQL中存储数据的底层文件,与上层的存储引擎进行交互,是文件的物理存储层。其存储的文件主要有:日志文件、数据文件、配置文件、MySQL的进行pid文件和socket文件等。
我们本次主要聚焦于server层,来了解mysql的执行过程
Mysql查询语句执行流程图

第一步,连接器
连接命令中的 mysql 是客户端工具,用来跟服务端建立连接。在完成经典的 TCP 握手后,连接 器就要开始认证你的身份,这个时候用的就是你输入的用户名和密码。
如果用户名或密码不对,你就会收到一个"Access denied for user"的错误,然后客户端程序 结束执行。
如果用户名密码认证通过,连接器会到权限表里面查出你拥有的权限。之后,这个连接里面的权限 判断逻辑,都将依赖于此时读到的权限。
连接完成后,你可以在 show processlist 命令中看到它。
第二步查缓存

查询缓存会针对同一条查询SQL语句,缓存它的结果。(mysql在8.0之后去掉了查缓存的功能)
mysql不推荐使用查缓存
第一个是查询SQL语句必须完全相同,SQL语句只要有有任何不同,比如多一个空格,大小写不同, 都会认为是不同的SQL语句,导致缓存不命中。
第二个是查询缓存的失效非常频繁,只要表结构有改动或者表中数据发生更新,那么与这个表有关 的所有的查询缓存都会被清空。
第三步,解析器和预处理
解析器和预处理本质上是对一个SQL语句编译 的过程,涉及词法解析、语法分析、语义分析等阶段。
如果查询缓存没有命中,接下来就需要进入正式的查询阶段了。客户端程序发送过来的请求事实 上只是一段文本而已,所以MySQL服务器程序首先需要对这段文本做分析,判断请求的语法是否 正确,然后从文本中将要查询的表、列和各种查询条件都提取出来
解析器
解析器的处理主要分为两个阶段
1,解析SQL
2,语法分析
解析SQL
Mysql通过将SQL语句进行解析,并生成一棵对应的解析树。MySQL解析器将使用MySQL语法分析(语法规则验证)和解析查询,如将验证是否使用错误的关键字,或者关键字的顺序是否正确
词法分析就是把一个完整的 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语法分析
解析器的第二步是根据词法分析结果,语法分析器会根据语法规则做语法检查,判断你输入的这个 SQL 语句是否满足 MySQL 语法。
如果你的语句不对,就会收到“You have an error in your SQL syntax”的错误提醒,比如下面 这个语句 select 少打了开头的字母“s”。
elect customer_id,first_name,last_name from customer where customer_id=14;ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'elect customer_id,first_name,last_name from customer where customer_id=14' at line 1预处理器
预处理器根据一些Mysql规则进一步检查解析树是否合法,如数据表和数据列是否存在,解析列名和别名,是否有歧义。接下来预处理器会验证用户权限(precheck)。查看用户是否有相应的操作权限。
第四步,查询优化器
查询优化器的作用就是根据解析树生成不同的执行计划,然后选择一种最优的执行计划,MySQL 里面使 用的是基于成本模型的优化器,哪种执行计划执行时成本最小就用哪种。
优化器都做哪些优化处理呢?
比如
1,当有多个索引可用,决定走哪个索引2,在一个语句有多表关联(join)的时候,决定各个表的连接顺序,以哪个表有基准表
第五步:Mysql根据相应的执行计划完成整个查询
Mysql根据执行计划给出的指令逐步执行。在此过程中,有大量的操作需要通过调用存储引擎实现的接口完成,这些接口即为“handler API”接口。查询中的每一个表由一个handler的实例表示。(实际上,在优化阶段Mysql就为每一个表创建了一个handelr实例,优化器可以根据这些实例的接口获取表的相关信息,如表的所有列名、索引统计信息等)
存储引擎接口完成例如:
比如我们这个例子中的表 T 中,ID 字段没有索引,那么执行器的执行流程是这样的:
1、调用 InnoDB 引擎接口取这个表的第一行,判断 ID 值是不是 10,如果不是则跳过,如果是则将这行存在结果集中;2、调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。3、执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。4、至此,这个语句就执行完成了
对于有索引的表,执行的逻辑也差不多。第一次调用的是“取满足条件的第一行”这个接口,之后循环取“满足条件的下一行”这个接口,这些接口都是引擎中已经定义好的