看了《MySQL高性能》以及几位博客大佬的博客。概要总结一下自己的理解。
先给出MySQL基本框架示意图,这张图的风格很喜欢,目前还不知道用什么画出来的,先用一下
咋一看图好像有点复杂,好像乱七八糟的。
不慌不慌,我们慢慢来,保证这篇看完就立马能大致全部了解了。
一般可以把MySQL分为Server层和存储引擎层两部分。
这一篇主要把Server层给弄清楚就可。
-
Server层:包含了连接器、查询缓存、分析器、优化器、执行器等,这里涵盖了MySQL的大多数核心功能区以及所有的内置函数。
- 内置函数:日期,时间,数学和加密函数等;
- 所有的跨存储引擎的功能都在这一层实现:存储过程、触发器、视图等。
-
存储引擎层:负责着数据的存储和提取,并提供了读写接口。不同的引擎有着各自的方式。
- create table时如果不指定引擎类型,默认使用的就是InnoDB。
接下来就是server层了。
一、连接器
功能就是负责跟客户端建立连接,获取权限,维持和管理连接。我们可以通过这个连接器呢,把客户端和server层连接起来,从而登录到mysql。
- 连接过程
- 经典的TCP握手之后,服务器会开始验证身份。这个时候要用到我们输入的用户名和密码
- 用户名密码正确,连接器就会回到权限表里找到我们所拥有的权限。之后在这个连接面里的权限判断逻辑,都会依赖于此时读到的权限。
- 连接完成之后
- 如果不进行后续操作,这个连接就会空闲下来。可以使用show processlist命令来查看它。
- 若很长时间都没有动静,那么连接器就会自动断开,这个时间默认的是8小时,是由wait_timeout控制的。
报告:我想修改wait_timeout时间,八小时太短了,满足不了我。
虽然很诧异,但是这是没有问题的啦
wait_timeout这个当然是可以手动更改的,更改方法如下
show global variables like 'wait_timeout'; -- 可查看当前wait_timeout时间为多少;
set global wait_timeout=36000; -- 修改wait_timeout为36000;
-- 当然咱们有图有真相。
关于上述的连接过程中连接器需要读的部分权限表
目前知道的这四个权限表
-
user权限表:记录允许连接到服务器的用户帐号信息,里面的权限是全局级的。
-
db权限表:记录各个帐号在各个数据库上的操作权限。
-
table_priv权限表:记录数据表级的操作权限。
-
columns_priv权限表:记录数据列级的操作权限。
关于长连接和短链接
-
长连接:指的就是长时间使用同一连接的情况,也就是连接成功后,长时间保持客户端与服务端的连接状态。
可表示为:
连接 -> 数据传输 -> 保持连接 -> 数据传输 -> 保持连接 … -> 关闭连接;
因此这就需要长连接在没有数据通信时,定时发送数据包,以维持连接状态。
-
短链接:在没有数据传输时直接关闭就行了。
可表示为:
连接 -> 数据传输 -> 关闭连接;
由于建立连接过程很复杂,所以我们尽量要减少建立连接的动作,也就是尽量使用长连接。
但是呢但是 长连接也存在着一个问题
-
如果全部使用长连接的话,会发现MySQL占用内存特别快。
为什么呢?
- 因为MySQL在执行的时候临时使用的内存时管理在连接对象里面的,这些资源只有在连接断开的时候会释放。所以若长连接链积累下来,就可能会导致内存占用太大。然后呢,就会被系统给强制杀死。
表现出来就是MySQL会异常重启
当然也有着解决方案
- 定期断开长连接。
不过如果使用的时MySQL5.7或者更高的版本的话。可以通过执行mysql_reset_connection来重新初始化链接资源。好的地方在这个过程不需要重连和重新做权限验证,而且还会将连接恢复到刚刚创建完时的状态。妙哉妙哉
查询缓存
简介一下:就是之前查询过的语句被记录下来了,当你再次使用那个语句时,就不需要进行下面的分析优化执行了,直接在缓存中找即可。
缓存是怎么被存的呢?
- 之前执行过的语句以及结果会以key-value对的形式,被直接存放在内存中。key是查询的语句,value是查询的结果。
看上去效率可高了呢。。
但其实大多数情况下我们都会不被建议使用查询缓存。
???为什么,明明这么好用的东西啊
别急别急看这里 (经过寻找各种大佬博客本蒻j终于找到了答案)
- 因为查询缓存的失效非常的频繁,只要有对一个表的更新,这个表上的所有查询缓存都会被清空。这就造成了这么一种现象:明明你费劲把结果存了起来,结果还没使用呢,就被一个更新全部清空了。对于频繁需要更新的数据库来说,查询缓存的命中率会非常的低。当然在某些静态表上,就是很久才会更新一次的表上,比如一个系统配置表,就比较适合使用查询缓存。
当不想使用查询缓存的时候,可以将参数query_cache_type设置成DEMAND。
这之后对于默认的SQL语句都不适用查询缓存了。当有些你确定要使用查询缓存的语句,可以用SQL_CACHE显示指定。比如
select sql_cache * from employee where salary = 3000;
ps:MySQL 8.0版本之后直接就将查询缓存的整块功能删掉了 ,也就是说从8.0开始就彻底没有这个功能了。
分析器
简介:如果没有命中缓存的话,就会开始真正的执行SQL语句了。分析器中简单的说包含了词法分析和语法分析。
给个例子分析一下
select * from employee where salary = 3000;
-
词法分析:分析器通过语法分析器,识别出了里面的字符分别是什么,代表着什么。
比如上面例子中,会将select这个关键字识别出来,首先知道这是条查询语句,然后把employee识别成表面employee,再把字符串salary识别成列ID,以此类推。最后识别出每个词。
-
语法分析:根据词法分析的结果,语法分析器会根据语法规则,判断输入的这个SQL语句是否满足MySQL语法。如果发现不满足,就会收到“you have an error in your SQL syntax”的错误提醒。
优化器
简介:经过上面的分析器,MySQL知道了需要做什么事儿了,但在开始做之前,还需要经过优化器的处理。
大概两个优化
- 优化器在表里面有多个索引时,决定使用哪个索引。
- 在一个语句有夺标关联(join)的时候,决定各个表连接的顺序。
选择更快的索引好理解,稍微有点绕口的时决定各个表连接的顺序。
举个栗子
select * from a join b using(id) where a.c=10 and b.d=20;
这个关联中
-
既可以先从表a中取出c=10的记录的ID值,再根据ID值关联到表b,再判断b里面d的值是否等于20。
-
也可以先从表b中取出d=20的记录的ID值,再根据ID值关联到表a,再判断a里面c的值是否等于10。
用不同的执行方法的逻辑结果是一样的,但是执行的效率会有不同。优化器就会决定选择使用哪一种方案,当然回旋执行效率高的。
执行器
简介:通过分析器知道了我是谁,我要干什么,通过优化器知道了我要怎么干我干的事情。于是到了执行器阶段,就要开始干活啦!
当然也不是说干就干,人家还是很正经有流程的
- 1、判断对这个表employee有没有查询的权限,如果没有,那当然不行的了,会返回没有权限的错误❌
- 2、要是判断出来有权限呢,就会打开表继续执行,打开的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。再提一嘴,默认引擎是InnoDB。然后就会顺着下去,根据引擎提供的流程,执行下去,最后找到我们想要的。
至此,整个流程就结束了。