mysql原理之执行流程深度解析


在一年前写过一篇关于mysql的执行流程和日志,现在再来回顾一下。
想看 Mysql原理-执行流程-binLog、redoLog、undoLog的作用-事务的四大特性请移驾至: https://blog.csdn.net/nxw_tsp/article/details/108307772

sql的执行流程

一条sql从你按下执行键那一刻开始到底发生了什么,你就能得到查询的结果呢?
在这里插入图片描述
通过上面这张图可以看出,sql执行其实并不是那么简单的就把返回结果给我们了,而是经过了很多复杂的步骤之后才把相应的结果返回给我们。

那么图中所说的query_cache、解析器、预处理、优化器、执行计划、执行器到底是什么呢?下面我来解释以下。

sql执行流程解释

  1. 从你点击执行sql的那一刻开始,Navicat需要对数据库进行一次连接请求。
  2. 请求成功后就会对query_cache缓存进行一次查询,看你当前sql的结果是否在缓存里面,如果有则直接返回数据。
  3. 没有缓存则会到Paser解析器里进行词法解析和语法解析并生成解析树。
  4. 解析完成后会来到预处理进行权限验证和对解析树进行语义解析,之后会把sql交给优化器进行优化。
  5. 优化器优化完成之后会交给执行计划来生成执行计划。
  6. 最后执行器负责按照执行计划拆解好的步骤去存储引擎里执行。
  7. 最后将结果返回客户端。

什么是query_cache、解析器、预处理、优化器、执行计划、执行器

query_cache(缓存)

官方文档地址:https://dev.mysql.com/doc/refman/5.7/en/query-cache-configuration.html
通过mysql官方文档可以看到在5.7.20版本之后query_cache是默认关闭的,甚至在5.8版本中直接把缓存给移除了。
在这里插入图片描述
当然,缓存的开启与否我们也是可以通过命令来查看的

show variables like 'query_cache%'

在这里插入图片描述

通过以上命令我们可以看到query_cache_type的值是OFF,说明是已经关闭了的,至于mysql为什么在5.7版本之后是关闭缓存的甚至于在后续的版本把缓存去掉,实际上是因为,在实际开发过程中我们对于数据的实时性的要求是很高的,如果当你第一次查询数据时直接把查询结果缓存下来之后,别的sql对你查询到的数据有修改的话,当你再一次执行该sql就直接从缓存里取到了(而结果仍然是未修改的),而不是从库里查询最新的数据结果。所以就造成了查询到的结果和真实数据不一致的情况。再一在实际的生产环境中,缓存当然要用专业的缓存工具,所以也就导致了后续版本中mysql将缓存剔除的情况。

Parser(解析器)

解析器通常会对我们的sql进行词法解析和语法解析。

词法解析会

词法解析就是把你输入的语句打碎成一个个的单词。
比如你输入一条简单的语句:

select employeeName from employees

词法解析会将sql打碎成四个单词。

语法解析

而当你输入一条规范的查询语句的时候,比如select name from users where id = 1
mysql就会对这条语句进行语法分析并生成解析树,select属于关键词,那么name是字段,from是关键词,users是表,where是关键词 id=1是条件。
解析完毕之后解析树大致如下
语法解析会解析出来关键字和非关键字。
在这里插入图片描述

Preprocessor(预处理器)

预处理器会进行权限的认证和语义解析。

权限认证

预处理器会判断你是否有执行select的权限或者insert,update的权限。

语义解析

刚才在解析器说过语法解析会对sql解析后生成一个解析树,但是解析器并不知道你查询的表是否存在,查询的字段是否正确,这个时候就会由预处理来进行验证,来确保你这条sql是可以执行的。

优化器

优化器会对sql进行一个优化,来达到最优。
比如:你users表有一个name和cardId的一个联合索引,
但是你sql写的是select * from users where cardId = 1 and name = ‘Silence’
根据最左匹配原则,这条sql是走不到联合索引的,但是优化器会对sql进行优化,优化为 select * from users where name = ‘Silence’ and cardId = 1
这样,sql执行的时候最终会用到这个联合索引。

执行计划

我们在一条sql前面加上Explain便会看到执行计划
例如我们输入sql

EXPLAIN select * from customer where address_id =(select address_id from address where phone = '745994947458')

在这里插入图片描述

执行计划如表中所示
它会告诉执行器,我这有两条语句,你先执行哪一条再执行哪一条。

主要的几个执行计划字段含义

id

执行计划的id id值越大优先级越高,越先被执行,如果id值一样,则从上到下依次执行,
如果sql中有子查询,则子查询的id值会大于最外层的主查询。

select_type

查询语句的类型,主要用来区分普通查询还是联合查询或者说是子查询等。

  • SIMPLE:简单的查询,查询中没有子查询或union的情况
    在这里插入图片描述
    一个简单的查询,他的select_type就是SIMPLE。

  • PRIMARY:主查询,如果有子查询的话最外层的就是PRIMARY

  • SUBQUERY:表示在select或者where包含了子查询在这里插入图片描述
    先把where条件的子查询查询出结果后,主查询再查子查询的结果。那么子查询的select_type就是SUBQUERY,最外层主查询的select_type是PRIMARY。

  • UNION:select 后的第二个查询

  • UNION RESULT:union的结果

UNION和UNION RESULT的展示如下:在这里插入图片描述 - DERIVED:是在查询FROM子句范围内生成表的表达式。例如,SELECT语句FROM子句中的子查询是派生表
在这里插入图片描述

table

查询中用到的表或者别名,中间数据。

type

访问的类型,SQL 查询优化中一个非常重要的指标,结果值从好到坏依次是:system > const > eq_ref > ref > range > index > ALL。

  • system:系统表
  • const:常量连接
  • eq_ref:主键索引(primary key)或非空的唯一索引
  • ref:非主键非唯一索引
  • range:范围查询
  • index:索引查询
  • ALL:全表扫描(full table scan)
possible_keys

查询过程中可能用到的索引

key

查询中真实用到的索引

关于执行计划更加详细的描述可以参考:https://www.cnblogs.com/yinjw/p/11864477.html
这篇文章写的非常棒非常细致。

执行器

执行器用来执行执行计划生成的计划,向存储引擎查询数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Silence-wen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值