欢迎光临散文网 会员登陆 & 注册

MySQL-基础架构

2023-03-15 23:17 作者:aiyounotbad  | 我要投稿

MySQL架构


大体来说,MySQL 可以分为 Server 层和存储引擎层两部分。

  • Server 层:包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。

  • 存储引擎层:负责数据的存储和提取。其架构模式是插件式的,支持 InnoDB、MyISAM、Memory 等多个存储引擎。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始成为了默认存储引擎。

通过一条sql查询语句,来看看Server层各部分都有些什么作用

1. 连接器

连接器主要负责跟客户端建立连接、获取权限、维持和管理连接

与服务端建立连接,然后开始验证身份,如果用户名与密码认证通过,则会查询出用户权限

在用户成功建立了连接之后,即使此时用户权限发生了变更,也不会影响到此时已存在连接的权限。只有新的连接才会使用新的设置。

数据库的连接

在数据库里,连接分为两种

  • 长连接:连接成功后,如果客户端持续有请求,则一直使用同一个连接

  • 短连接:每次执行完很少的几次查询就断开连接,下次查询再重新建立一个

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

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

如何解决?

  1. 定期断开长连接。使用一段时间,或者程序里面判断执行过一个占用内存的大查询后,断开连接,之后要查询再重连。

  2. 如果用的是 MySQL 5.7 或更新版本,可以在每次执行一个比较大的操作后,通过执行 mysql_reset_connection  来重新初始化连接资源。这个过程不需要重连和重新做权限验证,但是会将连接恢复到刚刚创建完时的状态。

2. 查询缓存

在8.0过后,MySQL直接将查询缓存的整块功能删掉

连接建立完成后,执行逻辑就会来到第二步:查询缓存。

MySQL  拿到一个查询请求后,会先到查询缓存看看,之前是不是执行过这条语句。之前执行过的语句及其结果以 k-v的形式,被缓存在内存中。key 是查询的语句,value 是查询的结果。

  • 如果你的查询能够直接在这个缓存中找到 key,那么这个 value  就会被直接返回给客户端。

  • 如果语句不在查询缓存中,就会继续后面的执行阶段。执行完成后,执行结果会被存入查询缓存中。

但是,缓存有着以下的规则

  1. 将查询语句和结果集返回到内存,下次再查直接从内存中取;

  2. sessions共享,一个client查询的缓存结果,另一个client也可以使用;

  3. SQL必须完全一致才会导致cache命中;

  4. 不确定的函数将永远不会被cache, 比如current_date, now等;

  5. 太大的result set不会被cache (< query_cache_limit);

  6. MySQL缓存在分库分表环境下是不起作用的;

  7. 执行SQL里有触发器,自定义函数时,MySQL缓存也是不起作用的;

  8. 在表的结构或数据发生改变时,基于该表相关cache立即全部失效。

  • 优点:

    Query Cache的查询,发生在MySQL接收到客户端的查询请求、查询权限验证之后和查询SQL解析之前。

    也就是说,当MySQL接收到客户端的查询SQL之后,仅仅只需要对其进行相应的权限验证之后,就会通过Query Cache来查找结果,甚至都不需要经过Optimizer模块进行执行计划的分析优化,更不需要发生任何存储引擎的交互。

    由于Query Cache是基于内存的,直接从内存中返回相应的查询结果,因此减少了大量的磁盘I/O和CPU计算,导致效率非常高。

  • 缺点:

    MySQL会对每条接收到的SELECT类型的查询进行hash计算,然后查找这个查询的缓存结果是否存在。虽然hash计算和查找的效率已经足够高了,一条查询语句所带来的开销可以忽略,但一旦涉及到高并发,有成千上万条查询语句时,hash计算和查找所带来的开销就必须重视了。

    Query Cache的失效问题。如果表的变更比较频繁,则会造成Query Cache的失效率非常高。表的变更不仅仅指表中的数据发生变化,还包括表结构或者索引的任何变化。

    查询语句不同,但查询结果相同的查询都会被缓存,这样便会造成内存资源的过度消耗。查询语句的字符大小写、空格或者注释的不同,Query Cache都会认为是不同的查询(因为他们的hash值会不同)。

    相关系统变量设置不合理会造成大量的内存碎片,这样便会导致Query Cache频繁清理内存。

  • 对性能的影响

    读查询开始之前必须检查是否命中缓存。如果读查询可以缓存,那么执行完查询操作后,会查询结果和查询语句写入缓存。当向某个表写入数据的时候,必须将这个表所有的缓存设置为失效,如果缓存空间很大,则消耗也会很大,可能使系统僵死一段时间,因为这个操作是靠全局锁操作来保护的。

    对InnoDB表,当修改一个表时,设置了缓存失效,但是多版本特性会暂时将这修改对其他事务屏蔽,在这个事务提交之前,所有查询都无法使用缓存,直到这个事务被提交,所以长时间的事务,会大大降低查询缓存的命中。

3. 分析器

如果没有命中查询缓存,就要开始真正执行语句了。

首先,MySQL 需要知道你要做什么,因此需要对 SQL 语句做解析

分析器先会做“词法分析”。你输入的是由多个字符串和空格组成的一条 SQL 语句,MySQL 需要识别出里面的字符串分别是什么,代表什么。

MySQL  从你输入的"select"这个关键字识别出来,这是一个查询语句。它也要把字符串“T”识别成“表名 T”,把字符串“ID”识别成“列  ID”。

做完了这些识别以后,就要做“语法分析”。根据词法分析的结果,语法分析器会根据语法规则,判断你输入的这个 SQL 语句是否满足 MySQL 语法。如果你的语句不对,就会收到“You have an error in your SQL syntax”的错误提醒。

在Oracle中,Oracle会在分析阶判断语句是否正确,表是否存在,列是否存在等,MySQL在设计上受Oracle影响颇深,同样在分析器阶段进行这些判断。

4. 优化器

MySQL 已经知道你要做什么了,在开始执行之前,还得知道该怎么做

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

对于这条sql,有两种执行方法:

  1. 先从表 t1 里面取出 c=10 的记录的 ID 值,再根据 ID 值关联到 t2,再判断 t2 里面 d 的值是否等于 20

  2. 先从表 t2 里面取出 d=20 的记录的 ID 值,再根据 ID 值关联到 t1,再判断 t1 里面 c 的值是否等于 10

优化器的作用就是决定使用哪个方法,因为这俩种方法的执行效率其实是不一样的

5. 执行器

分析器告诉了做什么,优化器知道了怎么做,接下来就是开始执行

执行前,会先判断对该表是否有查询的权限

没有权限,则

有权限,则打开表继续执行,打开对应引擎提供的接口

假如id没有索引,则执行流程如下

  1. 调用 InnoDB  引擎接口取这个表的第一行,判断 ID 值是不是  10,如果不是则跳过,如果是则将这行存在结果集中;

  2. 调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。

  3. 执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。

如果有索引,则是调用取“满足条件的第一行”这个接口,之后循环取“满足条件的下一行”这个接口


MySQL-基础架构的评论 (共 条)

分享到微博请遵守国家法律