架构概述在我们开始了解MySQL核心功能之前,首先我们需要站在一个全局的视角,来看SQL是如何运作执行的。通过这种方式,我们可以在头脑中构建出一幅MySQL各组件之间的协同工作方式,有助于我们加深对MySQL服务器的理解。根据逻辑架构图我们大致能将MySQL分为三层:第一层:主要做连接处理、授权认证、安全保障等第二层:涵盖了MySQL大多数核心服务功能,包括查询解析、分析、优化、缓存以及所有内置函数(例如:日期,时间,数学和加密函数等)。存储过程,触发器,视图等跨存储引擎的功能也都在这一层实现。第三层:存储引擎层,负责MySQL中的数据存储和提取。服务器通过API和存储引擎进行通信,API接口屏蔽了不同存储引擎之间的差异,使得这些差异对上层的查询过程透明。1、架构模块下面简要的聊一聊各个模块:连接器要访问数据库,首先要连接到数据库上,打交道的就是连接器。连接器负责跟客户端建立连接,获取客户端权限,身份认证,以及维持和管理连接。连接完成后,如果没有后续动作,会处于空闲状态,客户端太长时间没有动静,连接器会自动将连接断开,这个时间由参数wait_timeout控制,默认为8小时。连接器命令就是我们平时登录数据库的命令,写法如下mysql -h$ip -P$port -u$user -p查询连接状态,可以使用show processlist ,查看commend字段,如为Sleep,则意味着空闲。连接断开,再次请求时,则会提示 Lost connection to MySQL server during query。这个时候继续的话,就需要重新建立连接。数据库里所说的连接,分长连接和短连接。长连接:建立连接成功后,如果客户端持续有请求,则一直使用同一个连接。短连接:每次执行很少的几次查询就断开连接,下次执行再重新建立。由于建立连接是很复杂的,所以建议尽量使用长连接,但全部使用长连接也有一个弊端,表现的现象就是MySQL异常重启,主要原因是因为MySQL在执行过程中临时使用的内存是管理在连接对象里的,这些资源需要等到连接断开才会释放。长连接累积,会导致内存占用过大,被系统强制杀掉(OOM)。解决方式:定期断开长连接。版本>Mysql 5.7,可执行 mysql_reset_connection来重新初始化连接资源,该操作不需要重连和权限验证。查询缓存MySQL在执行查询语句前,会先去查询缓存查看之前是否执行过这条语句。执行结果一般会以key-value形式缓存在内存中,key是SQL语句,value是查询结果集,如果命中,会直接将value返回给客户端。显然,查询命中缓存就无需执行后面的复杂操作,效率会很高。然而这个功能实际上弊大于利,它最大问题在于失效频繁,只要表上有更新,这个表上所有查询缓存就都会被清空,所以对于更新频繁的表来说,查询缓存的命中率很低。除非是很长时间才会更新一次的静态表,比如系统配置表,才适合使用。因此大多数情况下建议不要使用MySQL的查询缓存,我们可以通过修改query_cache_type设置成DEMAND,关闭这个功能。如果想缓存结果,可以在客户端实现,例如利用mybatis自带的缓存功能,或者使用缓存中间件redis。值得一提的是,官方也考虑到查询缓存的弊端较多,在MySQL的8.0版本直接将查询缓存整个功能都删掉了。MySQL服务器团队的一篇博文有介绍,感兴趣的可以阅读下:https://mysqlserverteam.com/mysql-8-0-retiring-support-for-the-query-cache/分析器MySQL根据SQL语句来理解你的意图,首先需要对SQL语句做解析,主要是包括词法解析和语法分析这两步操作。词法解析对语句分词,解析出关键字;语法分析在词法解析的基础上基于语法规则进行检验。我们在执行SQL时经常碰到的提示“You have an error in your SQL syntax”,就是分析器检查出来的错误。优化器经过分析器解析后,在真正执行前还会经过优化器处理,选择最佳的执行计划。优化器可以选择不同的执行计划来提升执行的效率,例如选择使用哪个索引、决定各个表连接的顺序,它们最终执行的逻辑结果是一样,但是执行的效率会有不同。具体来说,优化器的执行流程分逻辑查询优化和物理查询优化两个阶段。逻辑查询优化:对SQL语句进行等价变换,对查询进行重写,而查询重写的数学基础就是关系代数。对条件表达式进行等价谓词重写、条件简化,对视图进行重写,对子查询进行优化,对连接语义进行了外连接消除、嵌套连接消除等。物理查询优化:关系代数的每一步都是物理计算,物理计算有很多种算法,通过计算各种物理路径的代价,选取代价最小的作为执行计划。查询优化器的两种优化方式查询优化器的目的就是生成最佳的执行计划,而生成最佳执行计划的策略通常有以下两种方式。第一种是基于规则的优化器(RBO,Rule-Based Optimizer),规则就是人们以往的经验,或者是采用已经被证明是有效的方式。通过在优化器里面嵌入规则,来判断SQL查询符合哪种规则,就按照相应的规则来制定执行计划,同时采用启发式规则去掉明显不好的存取路径。第二种是基于代价的优化器(CBO,Cost-Based Optimizer),这里会根据代价评估模型,计算每条可能的执行计划的代价,也就是COST,从中选择代价最小的作为执行计划。相比于RBO来说,CBO对数据更敏感,因为它会利用数据表中的统计信息来做判断,针对不同的数据表,查询得到的执行计划可能是不同的,因此制定出来的执行计划也更符合数据表的实际情况。但我们需要记住,SQL是面向集合的语言,并没有指定执行的方式,因此在优化器中会存在各种组合的可能。我们需要通过优化器来制定数据表的扫描方式、连接方式以及连接顺序,从而得到最佳的SQL执行计划。你能看出来,RBO的方式更像是一个出租车老司机,凭借自己的经验来选择从A到B的路径。而CBO更像是手机导航,通过数据驱动,来选择最佳的执行路径。执行器这个阶段才开始执行语句,在执行语句前会先判断对表有没有执行权限,如果有权限则打开表执行,执行器会使用对应存储引擎提供的接口来操作。举个例子select * from T where ID=10;ID字段没有索引,执行流程如下(有索引的也差不多):调用InnoDB引擎接口取这个表的第一行,判断ID值是不是10,如果不是则跳过,如果是则将这行存在结果集中;调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。慢查询日志里rows_examined字段即表示执行扫描行数的累加。总结今天我们了解MySQL的整体架构及各个功能模块,对一条SQL执行的大体流程有一个初步了解,下图为梳理的思维导图,可以快速的回顾温习一下。
本文出自快速备案,转载时请注明出处及相应链接。