MySQL - 01 一条SQL查询语句如何执行的?
MySQL的基础架构
MySQL可以大致分为Server层和存储引擎两部分,不同的存储引擎共用一个Server层
Server层
Server层涵盖了MySQL的大多数核心服务功能,如内置函数(日期,数学和加密),跨存储引擎功能(存储过程,触发器,试图等)等
包括:
- 连接器
- 查询缓存
- 分析器
- 优化器
- 执行器
连接器
连接器负责与客户端进行连接,获取权限,维持以及管理连接
通常会使用下面的命令进行连接
mysql -h[ip] -P[port] -u[user] -p
执行后,在交互对话输入正确密码即可连接成功。认证通过后,连接器会在权限表里查询你拥有的权限,之后此连接的权限判断逻辑依赖于此时读取到的权限。(这就是为什么之后更改权限不会再已登入的账号生效的原因)。
可以通过show processlist
命令查看连接信息
Command中的Sleep表示连接空闲,当空闲时间超过最大值时,连接就会将其自动断开,超时时间由wait_timeout
控制(默认为8小时)
通常建立一个连接较为复杂,因此尽量减少建立连接,使用长连接(长连接只是一种行为,使用就断开表示短连接,使用后不断开,保持较长的存活时间表示长连接)
而使用长连接也会存在问题,MySQL内存会涨的特别快,因为MySQL在执行过程中临时使用的内存保存在连接对象中,这些资源会在连接断开时被释放。所以由于长连接的积累,会导致内存占用过大而产生OOM被系统强行杀掉,导致MySQL异常重启,考虑如下解决方案:
- 定期断开长连接,或者通过程序判断,占用大内存的不使用长连接
- 如果是MySQL5.7及以上版本,可以通过
mysql_reset_connection
来初始化连接资源。此操作不需要重连和重新做权限认证,但是会将连接恢复到刚刚建立时的状态
~查询缓存~(8.0后被删除)
连接建立完成之后,就可以执行select
语句了,之后会进入查询缓存
之前执行过的查询语句及其结果会以key-value的形式缓存再内存中,如果能找到则讲value返回给客户端(返回时会做权限验证)
然后查询缓存虽然提高了查询效率,但是实际上是很低效的,查询缓存的失效很频繁,只要有对一个表进行更新操作,那么表上的所有缓存都会失效,对于更新较多的表来说,缓存命中率会非常低。
MySQL8.0版本直接将查询缓存整块功能进行了删除
分析器
如果查询缓存中没有结果(或者没有查询缓存),那么进入分析器,分析器主要对SQL语句进行解析
- 词法分析
分析SQL中每个词代表什么,如SELECT表示查询语句, "T"表示表明等 语法分析
判断SQL语句是否符合 MYSQL 的语法规范,包括表,字段是否存在等,如果不符合将报错
语法错误通常会提示第一处出现错误的位置报错会提示: You have an error in your SQL syntax
分析之后会进行一次权限校验,叫做precheck(做库权限校验)
优化器
经过分析器之后,MySQL就知道你要做什么了,但是真正的执行之前,还需要经过优化器处理
- 表里有多个索引时,决定使用哪个索引
- 一个语句中有多表关联时,决定各个表的连接顺序
执行器
知道做什么,怎么做之后,进入执行阶段
首先判断客户端对表是否有执行查询的权限,如果没有会返回没有权限错误(表权限校验)
如果有权限,就会打开表继续执行,打开表时会根据表的存储引擎定义,使用存储引擎提供的接口进行查询,流程如下:
- 调用InnoDB引擎接口取表的第一行,判断ID是否符合,不是则跳过,是则存入结果集
- 调用引擎接口取下一行,重复判断逻辑,直到表的最后一行
- 执行器将上述遍历过程中满足条件的行组成结果集作为结果返回给客户端
存储引擎层
存储引擎层负责数据的存储和提取。架构模式是插件式的,支持InnoDB,MyISAM,Memory等多种存储引擎。最常用的为InnoDB,从MySQL5.5.5版本之后InnoDB成为默认存储引擎
总结
把图也拿上来:
总结就是
- 连接器首先校验账号密码,建立连接,拉取权限信息
- 连接建立后,查看查询缓存是否有对应的语句存在,有则返回(返回时会对权限进行校验)
- 查询缓存没有,则分析器进行语法分析,词法分析,如果有错误则会报错
- 分析完成之后,优化器会对语句进行处理,如选择索引,选择先关联的表等
- 最后知道要做什么,怎么做之后,进入执行器,执行器会判断表使用的存储引擎并且调用存储引擎提供的接口,对数据进行检索查询