MySQL 中的 SQL 执行流程(5.7 之前的版本)

文章目录

      • 第一步:查询缓存判断是否被命中
      • 第二步:解析器进行语法及语义分析
      • 第三步:优化器确认 SQL 执行方式
      • 第四步:执行器执行 SQL

当执行一条查询 SQL 时,MySQL 5.7 之前的版本的 SQL 执行流程可以用下图进行概括:

MySQL 中的 SQL 执行流程(5.7 之前的版本)_第1张图片

以下对上图中的每一步进行分析。

第一步:查询缓存判断是否被命中

SQL 执行的第一步是 MySQL 服务端从 查询缓存 中检查当前需要执行的 SQL 能否命中查询缓存。MySQL 查询缓存的本质是将 SQL 及对应的执行结果,以键值对形式存入到内存中,如果发现需要执行的 SQL 在查询缓存中已存在该 SQL 及对应的执行结果映射,则直接从内存中取出数据进行返回。

根据 SQL 是否命中查询缓存将进行如下不同处理。

  • 当命中查询缓存时:即查询缓存中存在当前 SQL 与执行结果的映射,则直接将查询缓存中该 SQL 对应的查询结果返回给客户端。
  • 未命中查询缓存时:即查询缓存中不存在当前 SQL 与执行结果的映射,向下一步执行,即进入到解析器阶段。

但实际上查询缓存的命中率并不高,主要由以下两个方面的原因导致:

  1. SQL 一旦发送变化,就将导致查询缓存中以 SQL 及查询结果的键值对映射失效。
  2. SQL 访问对应表的表结构或表数据发生变更(包括 INSERTUPDATEDELETETRUNCATE TABLEALTER TABLEDROP TABLEDROP DATABASE 等),都将导致查询缓存中以 SQL 及查询结果的键值对映射失效。

查询缓存是 MySQL 8.0 前的版本特有的逻辑。因为查询缓存的命中率并不高的原因,所以在 MySQL 8.0 版本中,该功能被抛弃。

需要注意的是,并不是任何 SQL 及其执行结果都会被放入到查询缓存中。当查询请求中包含某些用户自定义变量或函数、系统函数、系统表时,都将使查询缓存失效,及查询结果并不会放入到查询缓存中。不将这些内容放入到查询缓存中,是由于这些内容的执行结果可能会发生变化,导致同一条查询 SQL 的执行获得了不同的查询结果。例如,查询请求中包含对日期函数 NOW() 的调用,而 NOW() 的结果每时每刻都不同。

可以通过如下 SQL 查看 query_cache_type 参数的值以确认查询缓存是否开启:

SHOW variables LIKE '%query_cache_type%';

该命令的执行结果 Value 即说明当前数据库实例中查询缓存是否开启,值为 On 说明查询缓存开启,值为 OFF 说明查询缓存关闭。

例如:

在这里插入图片描述

以上案例中,Value 列值为 OFF 即代表当前数据库实例下的查询缓存是关闭的。

第二步:解析器进行语法及语义分析

解析器又被称为分析器,当查询缓存未命中时,SQL 的执行进入第二阶段。第二阶段由解析器将对 SQL 进行语法及语义分析。

该阶段由两个步骤组成:

  1. 词法分析:传入的 SQL 语句本质上是多个字符串与空格的组合,解析器将这些字符串与空格解析为对应 MySQL 中的含义。

    例如:

    SELECT * FROM student WHERE id = 5;
    

    上述 SQL 案例,其中的 SELECT 将被解析器识别为一个查询类型的 SQL、student 将被识别为当前数据库下的一张表等等。

  2. 语法分析:判断传入 SQL 是否符合 MySQL 语法。当语法有误时,MySQL 将抛出 You have an error in your SQL syntax... 的错误提示。

    例如:

    SELECT * FORM sys_user;
    

    上述 SQL 案例将 FROM 故意错写为 FORM,SQL 的执行结果为:

    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 'FORM sys_user' at line 1
    

第三步:优化器确认 SQL 执行方式

一条查询 SQL 可以有多种执行方式且多种执行方式的最终返回结果都是相同的,优化器的职责是分析得到最优的执行计划。优化器通过选择 SQL 执行的最优计划,确认 SQL 以何种方式执行,从而减少 SQL 查询在数据库系统层面的各项开销。在优化器中,SQL 的执行方式将会被确认。

具体而言,优化器的主要作用有:

  1. 如果当需要访问的表存在多个索引,该选择何种索引;
  2. 存在多表连接(JOIN)时,各个表的连接顺序;
  3. 子查询转为连接、外连接转为内连接;

除了上述的作用,优化器还有表达式简化等功能。

此外,查询优化器可分为逻辑查询优化阶段与物理查询优化阶段。

  • 逻辑查询优化:指的是改变 SQL 语句内容从而使 SQL 查询更高效,同时为物理查询优化提供更多的候选执行计划。通常采用的方式是对 SQL 语句进行等价交换,对查询进行重写,而查询重写的数学基础就是关系代数。对条件表达式进行等价谓词重写、条件简化,对视图进行重写,对连接语义进行外连接消除、嵌套消除等。
  • 物理查询优化:指的是基于关系代数进行的查询重写,而关系代数的每一步都对应物理计算,这些物理计算往往存在多种算法,因此需要计算各种物理路径的代价,从而选择代价最小的作为执行计划。在该阶段中,对于单表与多表连接的操作,需要高效地使用索引以提高查询效率。

第四步:执行器执行 SQL

执行器将首先检查当前用户是否拥有权限,根据是否拥有权限做不同的处理:

  • 当前用户无权限:返回权限错误。
  • 当前用户有权限:继续向下处理。

检查完当前用户权限后,若当前用户有权限,执行器将打开 MySQL 数据表,在打开 MySQL 数据表时将会根据表存储引擎的定义调用相关存储引擎 API 对表进行数据查询并返回结果。

需要注意的是,在 MySQL 8.0 以下版本中,在查询缓存开启的情况下,则会将返回数据放入查询缓存中。

你可能感兴趣的:(MySQL,mysql,sql,数据库,后端)