MySQL 基础架构 1. 一条SQL查询语句的执行过程(个人学习笔记)

  • MySQL的逻辑架构图;

 

  MySQL 大体分为 “server 层” 和 “存储引擎层” 两部分;

  Server 层 

  包括 连接器、查询缓存、分析器、优化器、执行器 等,涵盖MySQL的大多数核心服务

  功能,以及所有的内置函数(日期,时间,数学,加密函数等),所有夸存储引擎的功能都可以

  在这一层实现,例如:存储过程,触发器,视图等;

 

  存储引擎层 

  负责数据的存储和提取,使用插件式的架构模式;支持 InnoDB、MyISAM、Memory 等多个存储引擎

  现在最常用的存储引擎是 InnoDB ,从MySQL 5.5.5 版本开始 InnoDB 是默认存储引擎。

 

  连接器

  连接器负责跟客户端建立连接,获取权限,维持和管理连接;一般写法如下:

mysql -h 192.168.5.116 -P 3306 -u root -p123456

  在完成经典的TCP三次握手之后,MySQL就会根据提供的凭证来验证用户身份,若验证失败则会收到

  一个”Access denied for user”的错误,然后客户端程序执行结束;若验证通过 连接器会到权限表中获取

  你所拥有的操作权限;之后这个连接里权限判断逻辑都依赖于此时读取的权限;若此时管理员对这个用

  户的权限做了修改,也不会影响已经存在连接的权限,修改完成后,只有下次新建连接才会使用新的权限;

   

  连接完成后若没有后续操作,则该链接成为空闲连接,可以使用  show processlist  命令 查看;客户端若

  太长时间没有后续操作,连接器会自动断开该连接,这个时间是由参数:wait_timeout 控制的,默认8小时;huo

  若断开连接后,客户端继续请求的话:则会收到一个错误提示(Lost connection to MySQL server during query)

  这时候如果要继续则需要重新连接MySQL;

 

  数据库中,长连接是指:连接成功后,客户端持续有请求则一直使用同一个连接;短连接则是指:每次执行完

  很少的几次查询就断开连接,下次查询就重新建立连接;

  

  新建连接的过程比较复杂,所以在使用过程中尽量减少建立连接的动作,也就是尽量使用长连接;

  但是全部使用长连接之后,可能会导致MySQL占用内存会涨的很快,这是因为MySQL在执行过程中临时使用的

  内存是管理在连接对象里的,这些资源会在连接断开的时候才会释放;所以长时间累积下来 可能导致内存占用

  过大而被系统强杀(OOM);从现象看就是MySQL异常重启了

  解决该问题可考虑一下俩方案:

  •   定期断开长连接:使用一段时间,或者程序里面判断执行过一个占用内存大的查询后,断开连接,之后重新连接;     
  •        若你的MySQL版本是 5.7 及以上 可以再每次执行一个较大的操作后,通过执行 “

    mysql_reset_connection”来重新

    初始化链接资源这个时候不需要重新连接和重新验证权限但是会将连接恢复到刚刚创建连接的状态

 查询缓存

  MySQL 拿到一个查询请求后会到查询缓存中看看之前有没有执行过这条查询语句,(之前执行过的语句会以 key-value 的形式直接缓存在内存中,key 是查询语句,value 是查询结果);

  如果这个查询语句(key)恰巧在缓存中,查询缓存会直接将这个key的value返回给客户端;如果查询语句不在缓存中就会继续后面的执行阶段,执行完成后执行结果会存入查询缓存中;

  “查询缓存的失效非常频繁”,只要对某个表进行过更新操作那么这个表的所有查询缓存都会清空,因此不建议使用查询缓存,况且 MySQL 8.0 版本直接将查询缓存干掉了 :(  

 分析器

  没有命中查询缓存则该真正执行查询语句了

  首先分析器会先做 ‘词法分析’ 分析SQL语句字符串中的关键字,是select还是insert等等,做完词法分析后就开始语法分析;根据词法分析的结果 语法分析器会根据语法规则判断SQL语句是否满足MySQL的语法。

 优化器

  经过分析器后MySQL就知道了这条SQL语句要干什么了,在开始执行之前还要经过优化器的处理;

  优化器是在表里有多个索引的时候决定使用哪个索引,或者一个语句有多表关联(join)的时候,决定各个表的连接顺序;

  例如:

mysql> select * from t1 join t2 using(ID)  where t1.c=10 and t2.d=20;
  • 既可以先从表 t1 里面取出 c=10 的记录的 ID 值,再根据 ID 值关联到表 t2,再判断 t2 里面 d 的值是否等于 20。
  • 也可以先从表 t2 里面取出 d=20 的记录的 ID 值,再根据 ID 值关联到 t1,再判断 t1 里面 c 的值是否等于 10。

  这两种方法的结果是一样的,但执行的效率不同,而优化器的作用就是决定执行那种方案。

执行器

  SQL语句经过了前面的流程,MySQL就知道了要做什么,该怎么做,接下来就要做了:

  首先执行器会判断当前用户对这张表有没有响应的操作权限,若没有就会返回没有权限的错误(若查询缓存命中了,会先判断权限),有权限则打开表继续执行;

  打开表的时候执行器会根据表的引擎定义去使用这个引擎提供的接口;

  例如:

mysql> select * from T where ID=8;

 

  比如我们这个例子中的表 T 中,ID 字段没有索引,那么执行器的执行流程是这样的:

  1. 调用 InnoDB 引擎接口取这个表的第一行,判断 ID 值是不是 10,如果不是则跳过,如果是则将这行存在结果集中;
  2.    调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。
  3.    执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。

至此SQL语句执行完成。