美文网首页
MySQL - 架构图

MySQL - 架构图

作者: kyo1992 | 来源:发表于2021-04-16 08:42 被阅读0次

    从一条SQL查询过程讲起MySQL架构图

    架构图

    Mysql逻辑架构图
    • Server 层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。
    • 存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持 InnoDB、MyISAM、Memory 等多个存储引擎。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始成为了默认存储引擎。

    连接器

    我们要进行查询,第一步就是先去链接数据库,那这个时候就是连接器跟我们对接。
    他负责跟客户端建立链接、获取权限、维持和管理连接。
    链接的时候会经过TCP握手,然后身份验证,然后我们输入用户名密码就好了。
    验证ok后,我们就连上了这个MySQL服务了,但是这个时候我们处于空闲状态。

    查看空闲连接

    show processlist,其中的Command列显示为Sleep的这一行,就表示现在系统里面有一个空闲连接。


    客户端如果太长时间没动静,连接器就会自动将它断开。这个时间是由参数 wait_timeout 控制的,默认值是 8 小时。

    如果在连接被断开之后,客户端再次发送请求的话,就会收到一个错误提醒: Lost connection to MySQL server during query。这时候如果你要继续,就需要重连,然后再执行请求了。

    数据库里面,长连接是指连接成功后,如果客户端持续有请求,则一直使用同一个连接。短连接则是指每次执行完很少的几次查询就断开连接,下次查询再重新建立一个。

    建立连接的过程通常是比较复杂的,所以我建议你在使用中要尽量减少建立连接的动作,也就是尽量使用长连接。

    但是全部使用长连接后,你可能会发现,有些时候 MySQL 占用内存涨得特别快,这是因为 MySQL 在执行过程中临时使用的内存是管理在连接对象里面的。这些资源会在连接断开的时候才释放。所以如果长连接累积下来,可能导致内存占用太大,被系统强行杀掉(OOM),从现象看就是 MySQL 异常重启了。

    怎么解决这个问题呢?可以考虑以下两种方案。

    • 定期断开长连接。使用一段时间,或者程序里面判断执行过一个占用内存的大查询后,断开连接,之后要查询再重连。
    • 如果用的是 MySQL 5.7 或更新版本,可以在每次执行一个比较大的操作后,通过执行 mysql_reset_connection 来重新初始化连接资源。这个过程不需要重连和重新做权限验证,但是会将连接恢复到刚刚创建完时的状态。

    查询缓存

    MySQL拿到一个查询请求后,会先到查询缓存看看,之前是不是执行过这条语句。
    同一条语句在MySQL执行两次,第一次和后面的时间是不一样的,后者明显快一些,这就是因为缓存的存在。
    跟Redis一样,只要是你之前执行过的语句,都会在内存里面用key-value形式存储着。
    查询的时候就会拿着语句先去缓存中查询,如果能够命中就返回缓存的value,如果不命中就执行后面的阶段。

    但是大多数情况下不要使用查询缓存,为什么呢?因为查询缓存往往弊大于利。

    查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会被清空。因此很可能你费劲地把结果存起来,还没使用呢,就被一个更新全清空了。对于更新压力大的数据库来说,查询缓存的命中率会非常低。除非你的业务就是有一张静态表,很长时间才会更新一次。比如,一个系统配置表,那这张表上的查询才适合使用查询缓存。

    MySQL 也提供了这种“按需使用”的方式。你可以将参数 query_cache_type 设置成 DEMAND,这样对于默认的 SQL 语句都不使用查询缓存。而对于你确定要使用查询缓存的语句,可以用 SQL_CACHE 显式指定,像下面这个语句一样:

    mysql> select SQL_CACHE * from T where ID=10;
    

    有个小技巧就是,开发的时候,都会去库里看看sql执行时间,但是可能是有缓存的,一般就在sql前面使用SQL_NO_CACHE就可以知道真正的查询时间了。

    mysql> select SQL_NO_CACHE * from T where ID=10;
    

    需要注意的是,MySQL 8.0 版本直接将查询缓存的整块功能删掉了,也就是说 8.0 开始彻底没有这个功能了。

    分析器

    在缓存没有命中的情况下,就开始执行语句了,你写的语句有没有语法错误,这是接下来MySQL比较关心的点。

    Mysql会先做词法分析,语句有这么多单词、空格,MySQL就需要识别每个字符串所代表的是什么,是关键字,还是表名,还是列名等等。

    然后就开始语法分析,根据词法分析的结果,语法分析会判断你sql的对错,错了会提醒你的,并且会提示你哪里错了。

    优化器

    经过了分析器,MySQL 就知道你要做什么了。在开始执行之前,还要先经过优化器的处理。

    优化器是在表里面有多个索引的时候,决定使用哪个索引,主键索引还是联合索引等等;或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序。比如你执行下面这样的语句,这个语句是执行两个表的 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。

    这两种执行方法的逻辑结果是一样的,但是执行的效率会有不同,而优化器的作用就是决定选择使用哪一个方案。

    执行器

    首先判断用户是否有对该表执行的权限。

    然后就是操作引擎,执行的时候,就一行一行的去判断是否满足条件,有索引的执行起来可能就好点,一行行的判断就像是接口都提前在引擎定义好了,所以比较快。

    数据库的慢日志有个rows_examined字段,扫描多少行可以看到,还有explain也可以看到执行计划,我们扫描了多少行。

    相关文章

      网友评论

          本文标题:MySQL - 架构图

          本文链接:https://www.haomeiwen.com/subject/tdfikltx.html