全面理解mysql架构

96 阅读7分钟

客户端

navicat、sqlyog、jdbc等,都属于客户端,用于连接服务端发送执行sql语句的请求。

服务端

服务端可分为Server层和存储引擎层,Server层包括连接器、查询缓存、分析器、优化器、执行器。内置函数、视图、存储过程、触发器等具有跨存储引擎的功能都在这一层实现。

存储引擎层

  • 复制数据的存储和检索。
  • 支持多种存储引擎,InnoDB、MySAM、Memory等,每种引擎适用场景不一样。
  • InnoDB是mysql5.1以上的默认存储引擎,它支持事务、行级锁定和外键约束。InnoDB有自己的日志系统,redolog(重做日志)和undolog(撤销日志)。redolog用于保证事务的持久性,在数据库崩溃后可以用来恢复数据,undolog用于支持事务的原子性和多版本并发控制(MVCC)。

Server层

  • 负责sql语句解析优化和缓存。
  • 权限管理、用户认证。
  • 提供sql函数和存储过程。
  • 提供复制备份恢复等高级功能。
  • 有自己的日志系统,binlog(归档日志)。记录了所有修改数据库数据的语句(insert、update、delete)的信息。不包括select、show等查询语句。binlog主要用于复制和恢复操作。

连接器

负责与客户端建立连接、获取权限和维持管理连接。客户端长时间无操作连接器会自动断开连接。在断开时候执行sql会出现“Lost connection to MySQL server during query”的错误。等待时间由wait_timeout参数控制,默认约为8小时,可以在my.cnf配置单位为秒

[mysqld]
wait_timeout = 28800;

查看当前设置

SHOW VARIABLES LIKE 'wait_timeout';

查看当前数据库连接状态

SHOW processlist;

或者使用命令临时设置

  • 设置当前会话生效
SET SESSION wait_timeout = 28800;
  • 设置本次启动生效
SET GLOBAL wait_timeout = 28800;

查询缓存

在mysql5.6、5.7sql语句为key进行缓存 常用变量说明:

变量名含义
query_cache_type是否启用(0=关闭,1=按需,2=强制)
query_cache_size缓存区域大小(单位:字节)
query_cache_limit单个查询最大可缓存大小

MySQL 8.0 及以后彻底移除 Query Cache。查询缓存看起来很香,但存在几个问题:

  1. 缓存命中要求太苛刻,SQL 语句必须完全相同
  2. 写操作会清除缓存,大大降低了使用价值
  3. 加锁机制复杂,容易引起性能瓶颈
  4. 现代架构中,更推荐使用外部缓存(如 Redis)

分析器

缓存未命中则执行分析器,分析器会对执行语句做词法分析,把SQL拆分成一个个“词”或“Token”,接着做语法分析检查语法是否合法,语法错误会报错:ERROR 1064 (42000): You have an error in your SQL syntax...

优化器

分析器分析语句正确后会进入优化器,优化器它决定SQL语句应该如何执行,才能获得最优的性能。

  1. 决定多表连接的顺序
  • 先连接哪两个表,再连接哪个表,顺序不同可能导致性能差异巨大。

  • 优化器会基于统计信息选择最优顺序。

  • 一般小表驱动大表

SELECT * FROM a JOIN b ON a.id = b.aid JOIN c ON b.id = c.bid;

1.子查询改写为 JOIN / 半连接(semi-join)等 优化器可能会改写成JOIN来提升效率

SELECT * FROM students WHERE id IN (SELECT student_id FROM scores WHERE score > 90);

执行器

执行器是SQL执行流程的最后一个关键模块,负责根据优化器生成的执行计划,真正把数据“查出来/改下去”。 在开始执行时,先判断用户对这个语句和表有没有权限,没有就会返回权限错误,有就打开表继续执行。确保只有被授权的用户才能访问和操作数据。

  • 命中缓存,会在查询缓存结果的时候,做权限验证。
  • 在语法分析过程中,分析器会进行初步的权限检查。

执行器可以按如下方式读取数据(优化器决定):

方式说明
全表扫描(ALL)逐行读取整张表,性能差
索引查找(ref)用索引过滤特定行
唯一索引查找(const)只返回一行
范围查找(range)比如BETWEEN、<、> 这种条件

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

  1. 用引擎接口取表的第一行,判断条件是否满足,不满足则跳过,满足则存入结果集。
  2. 用引擎接口重复判断,一直到最后一行。
  3. 行器返回结果集给客户端。

为什么不在分析器直接做权限判断?

  • 职责分离:权限是基于连接和会话的,分析器只负责 SQL 语法检查,不涉及权限。
  • 性能优化:避免每次 SQL 执行时重复进行权限验证,减少不必要的性能开销。
  • 错误早期反馈:连接阶段的权限判断可以在 SQL 执行前就发现权限问题,提前反馈错误,优化用户体验。
  • 复杂sql分析器无法直接判断:可能涉及到视图,存储过程需要执行器才能知道有哪些语句哪些表。

Redolog是什么?

redolog(重做日志) 是InnoDB存储引擎特有的日志,用于记录事务对数据做的更改(逻辑或物理修改) ,即使事务尚未真正写入磁盘页。它可以在系统崩溃后“重做”这些操作,确保数据不会丢失。 Redolog 是保存在磁盘上的,默认文件名格式为:ib_logfile0 它是顺序写(速度相对idb数据文件随机写更快)也是循环写的,组成所谓 redolog buffer(在内存中,事务提交前会先写入这里) + redolog file(在磁盘中,周期性或事务提交时刷盘) 的结构

Binlog是什么?

Binlog(二进制日志) 是由 MySQL Server 层 生成的日志,用来记录所有对数据库产生更改的SQL语句或行数据变化,本质是逻辑日志,而非物理日志。 它的主要作用是:

  • 数据恢复:用于逻辑级别的恢复,比如基于时间点恢复
  • 主从复制:从库通过读取主库 binlog 实现同步
  • 审计:可审计数据库里发生了哪些变更 binlog 有 3 种格式:
格式描述特点
STATEMENT记录执行的 SQL 语句体积小,但不一定可重放,比如NOW()、UUID()
ROW记录行的变化(改了哪一行什么值)安全精准,但体积大
MIXED混合使用两种格式一般默认选用这个

mysql内部的两阶段提交

image.png

redolog持久化到磁盘后会标志自己处于prepare阶段,在执行器也调用fsync将binlog cache持久化到binlog文件后,MySQL 服务器会向存储引擎发送提交事务的命令。存储引擎收到命令后,会将redolog的状态从prepare改为commit,并释放事务占用的资源,完成事务的提交。

这两个线程的工作是独立的,尽管它们都涉及到持久化操作,但它们处理的对象不同:

  • redolog 专注于数据库的物理存储,确保即使发生崩溃,未提交的事务能够恢复。
  • binlog 专注于记录数据库的逻辑操作,用于复制和恢复数据。

崩溃恢复规则:

  1. redolog事务完整,处于commit阶段,则直接提交。
  2. redolog处于prepare,判断对应事务的binlog文件是否存在并完整,如果是就提交事务,不是就是回滚事务。