【MySQL】01. MySQL 架构

in #studylast month

本文将深入剖析 MySQL 的体系结构,重点介绍服务端中 Server 层和存储引擎层的关键组件和它们的功能。通过本文的探讨,读者将获得对 MySQL 架构的全面认识,为后续深入学习 MySQL 的索引、查询优化、事务处理等高级特性打下坚实的基础。

1 MySQL整体架构

以下是 MySQL 架构的主要组成部分:

  • 客户端:连接工具(Navacat、SQLyog、JDBC)都归纳为MySQL客户端(Client),主要用于发送执行sql语句的请求。
  • 服务端:服务端是 MySQL 的核心,负责处理客户端的请求并返回结果。服务端架构主要分为Server 层存储引擎
    • Server层:包括 MySQL 的大部分核心服务,如 SQL 语法解析、查询优化、缓存机制等。
    • 存储引擎:负责数据的存储、索引、事务管理等,支持多种存储引擎,如 InnoDB、MyISAM、Memory 等。
  • 数据文件:存储引擎所管理的数据文件,包括表数据文件、索引文件等。

image.png

接下来我们将重点探讨服务端的两个核心层次:Server 层和存储引擎层。这两个层次共同协作,为 MySQL 提供了强大的数据处理能力和灵活性。

2 Server层

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

  • 负责处理 SQL 语句、解析、优化、缓存等。
  • 负责权限管理、用户认证等。
  • 提供了各种 SQL 函数和存储过程。
  • 提供了复制、备份、恢复等高级功能。
  • Server 层有自己的日志系统,称为 binlog(归档日志)。binlog 记录了所有修改数据库数据的 SQL 语句(如 INSERT、UPDATE、DELETE 等)的信息,但不包括 SELECT 和 SHOW 这类查询语句。binlog 主要用于复制和恢复操作

2.1 连接器

连接器负责跟客户端建立连接、获取权限、维持和管理连接。连接命令一般是这么写的:

mysql -h$ip -P$port -u$user -p

输完命令之后,就需要在交互对话里面输入密码。

连接命令中的 mysql 是客户端工具,用来跟服务端建立连接。在完成经典的 TCP 握手后,连接器就要开始认证你的身份,这个时候用的就是你输入的用户名和密码。

  • 如果用户名或密码不对,你就会收到一个Access denied for user的错误,然后客户端程序结束执行。
  • 如果用户名密码认证通过,连接器会到权限表里面查出你拥有的权限。之后,这个连接里面的权限判断逻辑,都将依赖于此时读到的权限。

连接MySQL用户名或密码不对报错.png

客户端如果太长时间没动静,连接器就会自动将它断开。这个时间是由参数 wait_timeout 控制的,默认值是 8 小时。如果在连接被断开之后,客户端再次发送请求的话,就会收到一个错误提醒: Lost connection to MySQL server during query。这时候如果你要继续,就需要重连,然后再执行请求了。

-- 查看数据库的连接状态 
show processlist; 
-- 查看当前的wait_timeout参数值 
SHOW VARIABLES LIKE 'wait_timeout';

2.2 查询缓存

在MySQL5.7版本,连接完成后就会进入查询缓存,在MySQL 8.0 版本将查询缓存功能删掉了

在进行查询操作时,会先到查询缓存看看是不是执行过这条语句。之前执行过的查询语句及其结果可能会以 key-value 对的形式缓存在内存中。其中 key 是查询的语句,value 是查询的结果。

如果命中查询缓存,会在查询缓存返回结果的时候,做权限验证。如果语句不在查询缓存中,就会继续后面的执行阶段。执行完成后,执行结果会被存入查询缓存中。可以看到,如果查询命中缓存,这个效率会很高。

在进行更新操作时,跟更新的表有关的查询缓存会失效。因此对于更新压力大的数据库来说,查询缓存的命中率会非常低。除非业务查询就是一张静态表,很长时间才会更新一次。比如,一个系统配置表,那这张表上的查询才适合使用查询缓存。

因此,MySQL 提供了按需使用的方式。相关参数如下:

  • query_cache_size:用于缓存的大小
  • query_cache_type:设置使用缓存的场景:
    • 0(OFF):全不使用query cache
    • 1(ON):除显式要求不使用 query cache 之外的所有的 select 都使用query cache,通过sql_no_cache 显示指定不使用缓存
    • 2(DEMOND):只有显示要求才使用query cache,通过 sql_cache 显示指定使用缓存

可以通过在 MySQL 命令行界面(CLI)中执行以下命令来设置 query_cache_typeDEMAND

SET GLOBAL query_cache_type = DEMAND;

或者,可以在 MySQL 的配置文件(通常是 my.cnf 或 my.ini)中设置,修改配置文件后需要重启 MySQL 服务来使更改生效。

query_cache_type = DEMAND

而对于确定要使用查询缓存的语句,可以用 SQL_CACHE 显式指定,对于默认的 SQL 语句都将不使用查询缓存。如下:

-- 只有这条带有 SQL_CACHE 提示的查询会被缓存。 
select SQL_CACHE * from user where id = 1;

MySQL 为什么在 8.0 版本中移除了查询缓存功能

  1. 锁粒度问题:当查询缓存开启时,如果对一张表进行写操作(比如插入、更新、删除),整个表的查询缓存将被失效,这可能导致锁住整个表而不是仅仅影响到那些被修改的部分。这在高并发环境中,可能会造成大量的阻塞,降低数据库的响应速度。
  2. 复杂的SQL查询:复杂的 SQL 查询语句往往不容易被缓存。当 SQL 查询中包含变量、函数、子查询或时间戳等动态内容时,这些查询难以在缓存中找到完全匹配的相同查询,因此缓存命中率较低。
  3. 数据更新频繁:如果数据库中的数据频繁更新(插入、更新、删除),那么查询缓存将更容易被清空或失效。一旦数据被修改,与该数据相关的缓存会被清除,导致缓存的命中率下降。
  4. 查询结果集较大:大型查询结果集不太可能被完全缓存,因为缓存的空间是有限的。如果查询结果集很大,即使一部分结果被缓存了,仍可能导致整个查询结果无法完全命中缓存。

2.3 分析器

若查询缓存未命中,则会执行分析器,来分析查询语句是否合法。

2.3.1 词法分析

  • 主要负责从 SQL 语句中提取关键字,比如:查询的表,字段名,查询条件等等。
  • 词法分析阶段是从 information_schema 里面获得表的结构信息的。

2.3.2 语法分析

做完了“词法分析”这些识别以后,就要做“语法分析”。

  • 进行一些初步的权限检查 precheck,例如验证用户是否有权访问指定的数据库和表。
  • 根据语法规则,判断输入的SQL 语句是否满足 MySQL 语法
  • 如果 SQL 语句不对,就会返回 You have an error in your SQL syntax 的错误提醒,一般语法错误会提示第一个出现错误的位置,所以你要关注的是紧接“use near”的内容。

语法分析报错提示.png

2.4 优化器

经过了分析器,若语句正确,就会进入优化器。优化器的作用是在基于同一个查询/更新语句的多个执行方案中找出效率最高的。比如,在表里面有多个索引的时候,决定使用哪个索引;在一个语句有多表关联(join)的时候,决定各个表的连接顺序。

比如你执行下面这样的语句,这个语句是执行两个表的 join:

-- USING等价于JOIN中on 
select * from t1 join t2 using(ID) where t1.c=10 and t2.d=20;

理论上有两种执行方案:

  1. 方案一:可以先从表 t1 里面取出 c=10 的记录的 ID 值,再根据 ID 值关联到表 t2,再判断 t2里面 d 的值是否等于 20。
  2. 方案二:可以先从表 t2 里面取出 d=20 的记录的 ID 值,再根据 ID 值关联到 t1,再判断 t1里面 c 的值是否等于 10。

这两种执行方案的逻辑结果是一样的,但是执行的效率会有不同,而优化器的作用就是决定选择使用哪一个方案。例如,如果t1表非常大而t2表非常小,那么优化器可能会选择方案2,因为它可以先快速地从t2中筛选出d=20的记录,然后使用这些ID值去t1中进行关联,这样可以大大减少t1表的扫描量。

2.5 执行器

MySQL 通过分析器知道了要做什么,通过优化器知道了该怎么做,于是就进入了执行器阶段,开始执行语句。

2.5.1 权限校验

开始执行的时候,要先判断对这个表有没有执行权限,如果没有,就会返回没有权限的错误。如果有权限,就打开表继续执行。这是一种安全机制,确保只有被授权的用户才能访问和操作数据。

select * from T where ID=10; 
ERROR 1142 (42000): SELECT command denied to user 'b'@'localhost' for table 'T'

有些时候,SQL语句要操作的表不只是SQL字面上那些。SQL执行过程中可能会有触发器这种在运行时才能确定的过程,在语法分析阶段是不能对这种运行时涉及到的表进行权限校验的,所以需要在执行器阶段进行权限检查。

2.5.2 执行语句

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

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

至此,整个语句就执行完成了。

3 执行引擎

存储引擎负责数据的存储和检索。其架构模式是插件式的,以下是 MySQL 中常见的几种存储引擎:

  1. InnoDB:支持事务处理、行级锁定和外键约束,索引和数据统一存储。从 MySQL5.5.5 版本开始成为了默认存储引擎。
  2. MyISAM:非事务型存储引擎,提供高速的读取和写入操作,不支持事务。索引和数据分开存储
  3. Memory:将所有数据存储在内存中,提供极快的数据访问速度,但数据安全性较低。

4 结语

通过本篇文章,我们深入了解了 MySQL 的体系结构,包括 Server 层和存储引擎层的组成及其功能。理解这些组件的工作原理对于优化 MySQL 数据库的性能和设计高效的数据库解决方案至关重要。在接下来的博文中,我们将深入探讨 MySQL 的索引机制、日志系统、事务处理等更多核心概念。

Coin Marketplace

STEEM 0.18
TRX 0.13
JST 0.030
BTC 57962.42
ETH 3050.85
USDT 1.00
SBD 2.25