客户端
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。查询缓存看起来很香,但存在几个问题:
- 缓存命中要求太苛刻,SQL 语句必须完全相同
- 写操作会清除缓存,大大降低了使用价值
- 加锁机制复杂,容易引起性能瓶颈
- 现代架构中,更推荐使用外部缓存(如 Redis)
分析器
缓存未命中则执行分析器,分析器会对执行语句做词法分析,把SQL拆分成一个个“词”或“Token”,接着做语法分析检查语法是否合法,语法错误会报错:ERROR 1064 (42000): You have an error in your SQL syntax...
优化器
分析器分析语句正确后会进入优化器,优化器它决定SQL语句应该如何执行,才能获得最优的性能。
- 决定多表连接的顺序
-
先连接哪两个表,再连接哪个表,顺序不同可能导致性能差异巨大。
-
优化器会基于统计信息选择最优顺序。
-
一般小表驱动大表
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、<、> 这种条件 |
打开表的时候,执行器就会根据表的引擎定义,去使用引擎提供的接口:
- 用引擎接口取表的第一行,判断条件是否满足,不满足则跳过,满足则存入结果集。
- 用引擎接口重复判断,一直到最后一行。
- 行器返回结果集给客户端。
为什么不在分析器直接做权限判断?
- 职责分离:权限是基于连接和会话的,分析器只负责 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内部的两阶段提交
redolog持久化到磁盘后会标志自己处于prepare阶段,在执行器也调用fsync将binlog cache持久化到binlog文件后,MySQL 服务器会向存储引擎发送提交事务的命令。存储引擎收到命令后,会将redolog的状态从prepare改为commit,并释放事务占用的资源,完成事务的提交。
这两个线程的工作是独立的,尽管它们都涉及到持久化操作,但它们处理的对象不同:
- redolog 专注于数据库的物理存储,确保即使发生崩溃,未提交的事务能够恢复。
- binlog 专注于记录数据库的逻辑操作,用于复制和恢复数据。
崩溃恢复规则:
- redolog事务完整,处于commit阶段,则直接提交。
- redolog处于prepare,判断对应事务的binlog文件是否存在并完整,如果是就提交事务,不是就是回滚事务。