TOC
本系列是「极客时间」课程「MySQL 实战 45 讲」的学习笔记,目的是为了强化学习效果;
Mysql 语句执行流程
下图是 MySQL 架构示意图,引用自极客时间的「MySQL实战45讲」
从示意图中,可以看出总体上 MySQL 架构由 Server 层和存储引擎层组成;
- 存储引擎层主要作用是存储和提取数据,且架构模式是插件式的,如:InnoDB, MyISAM, Memory 等引擎;
- Server 层涵盖了 MySQL 的大多数核心服务功能,所有的内置函数(日期,时间,数学,加密等),所有跨存储引擎的功能(存储过程,触发器,视图)
组件介绍
连接器
使用 MySQL 的第一步就是连接至服务端,这由连接器负责,其主要功能是与客户端建立连接,获取权限,维持和管理连接;
连接 MySQL 服务端命令如下
mysql -h$ip -P$port -u$user -p
建立连接步骤:
- 进行 TCP 连接;
- 连接器根据用户名,密码进行身份认证;
- 如果认证失败返回错误 “Access denied for user”
- 如果认证成功,连接器查询权限表获取所拥有权限,后续所有权限认证操作都依赖此时读到的数据;因此,如果连接后,修改用户权限,对已有的连接没有效果;
当建立连接成功后,如果客户端没有任何状态,则连接会显示 Sleep 状态;保持 Sleep 状态超过 wait_timeout「默认 8 小时」,服务端会自动断开连接;断开连接后,客户端再发送请求,则会收到错误提醒,客户端需要重新连接,发送请求;
数据库连接中,有长短连接之分;「长连接」指一次连接,如果客户端持续有请求,则始终使用同一连续;「短连接」指一次连接每次执行很少得请求则断开连接;
由于建立连接过程复杂,因此建议尽量使用长连接;但是 MySQL 执行过程中使用的临时内存是管理在连接中的,如果连接不释放,MySQL 会占用大量内存,累积下来容易导致内存过大,被系统强行杀掉;
解决长连接带来的占用内存方案有:
- 定期断开连接,或者程序判断如果执行了一个占用大内存的查询后自动断开连接,之后查询再重新连接;
- 如果 MySQL 版本大于 5.7,则可使用 「mysql_reset_connection」命令重新初始化连接资源,但是不需要重新连接和权限验证;
查询缓存
对于查询语句,建立连接成功后,执行第二步:查询缓存;
MySQL 会将执行过的查询语句以 key-value 的形式存储,key 为查询语句本身,value 为查询结果;如果命中查询缓存,则直接返回缓存结果;
尽管查询缓存能够避免后续复杂操作,但是大多数时候还是不建议使用查询缓存;原因是查询缓存太容易失效,只要对一个表更新,则关于此表的所有查询语句都失效;因此,对于更新频繁的表,可能还没再次查询就已经失效了;对于系统配置表,则可以使用查询缓存的方式;
MySQL 则提供了参数 「query_cache_type」达到按需使用的目的,将其设置为 DEMAND,则所有查询语句默认不走查询缓存,需要使用查询缓存的可以使用 「SQL_CACHE」显示指定,如
SELECT SQL_CACHE * FROM t WHERE ID = 10;
但注意的是 MySQL 8.0 已经完全移除查询缓存功能;
分析器
如果查询缓存没有命中,则就要正式执行查询语句;执行查询语句可以分为三大步骤:
- 分析器解决做什么问题;
- 优化器解决怎么做问题;
- 执行器解决执行问题;
为了解决做什么问题,分析器执行步骤如下:
- 第一步进行「词法分析」,将语句的关键字,字段,表名等提炼出来;
- 第二步进行「语法分析」,判断语句是否符合 MySQL 语法,如果不对,则会收到提示信息 「You have an error in your SQL syntax」;
优化器
通过分析器的词法分析,语法分析后,MySQL 进入优化器解决如何做的问题;优化器主要工作是,当表有多个索引时,决定使用哪个索引,多表关联时,决定先关联哪个表;
执行器
知道如何执行语句后,MySQL 进入执行器,开始执行语句,如果没有索引执行步骤如下:
- 检测是否有权限执行语句;如果命中查询缓存,会在返回结果时进行权限验证;查询语句也会在优化器被调用前,进行一次 precheck;
- 如果有权限,则调用引擎层接口获取表第一行数据;
- 判断数据是否符合,如果如何则加入结果集,重复执行逻辑调用引擎接口获取下一行直到最后一行;
- 返回结果集
对于有索引的数据,第一次调用接口「获取满足条件的第一行数据」,之后循环调用「满足条件的下一行数据」,最后返回结果集;