一条 SQL 更新语句是如何执行的?
SQL语句的执行过程涉及数据库的多个组件:连接器、分析器、优化器、执行器和存储引擎。理解这些组件的协作,对于深入掌握数据库性能优化和事务机制至关重要。
0. 前置知识回顾
查询语句执行流程:
连接器 → 查询缓存(已弃用) → 分析器(解析 SQL) → 优化器(选择执行计划) → 执行器(执行操作) → 存储引擎(读取/写入数据)
1. 示例:一个简单的更新语句
-- 创建表T,包含主键 ID 和一个整型字段 c
CREATE TABLE T (
ID INT PRIMARY KEY,
c INT
);
-- 将 ID=2 的记录中的 c 字段值加1
UPDATE T SET c = c + 1 WHERE ID = 2;
2. 更新语句的执行流程
和查询语句类似,更新语句也会经过 SQL 的各个组件流程。但更新语句除了读取数据,还会修改数据,因此会涉及到 日志系统 的处理。
流程简述如下:
- 连接器:建立客户端和数据库之间的连接。
- 查询缓存(现在已废弃):由于该语句会修改表数据,因此会使查询缓存失效,MySQL 会清空缓存中与表
T
相关的结果。 - 分析器:进行词法和语法分析,识别为一条
UPDATE
语句。 - 优化器:决定使用主键索引查找
ID=2
,优化执行路径。 - 执行器:调用存储引擎 API 执行更新操作。
3. 两种关键日志机制
更新语句执行过程中涉及两个关键日志:redo log
和 binlog
。
3.1 redo log(重做日志)
- 属于 InnoDB 存储引擎。
- 是 物理日志,记录“对某个页的物理修改”。
- 为了实现 WAL(Write-Ahead Logging)机制 —— 先写日志,再写磁盘,提高性能并保障数据可靠性。
WAL 示例流程:
- 更新请求到来,先将修改记录写入 redo log(处于 prepare 状态)。
- 数据页在内存中也被更新。
- 后续再异步将更新刷入磁盘。
特点:
- 固定空间:如由4个1GB文件组成,写满后循环使用。
- 使用两个指针:
write pos
:当前写入点checkpoint
:当前可擦除点(已持久化到磁盘)
Crash-safe 能力:即使数据库崩溃,重启后仍能通过 redo log 恢复数据,防止已提交事务丢失。
3.2 binlog(归档日志)
- 属于 MySQL Server 层。
- 是 逻辑日志,记录的是 SQL 语句本身或行变更内容。
- 所有存储引擎(如 MyISAM、InnoDB)都可使用。
特点:
- 支持复制(主从)、备份恢复、审计。
- 可追加写,不会覆盖之前的内容。
4. 更新语句完整执行流程
- 执行器调用存储引擎查找 ID=2 的记录;
- 将该行的
c
值加1,并提交修改请求; - InnoDB 引擎:
- 更新内存中该记录;
- 写入 redo log(prepare 状态);
- 执行器生成并写入 binlog;
- 执行器调用引擎提交事务,引擎将 redo log 改为 commit 状态;
- 更新成功完成。
5. 两阶段提交(2PC)
为了保持 redo log 与 binlog 的一致性,MySQL 引入“两阶段提交”机制:
步骤 | 内容 |
---|---|
① | 写入 redo log(prepare) |
② | 写入 binlog |
③ | redo log 标记为 commit |
为什么需要 2PC?
示例:
- 若只写 redo log,binlog 写入前 crash,则主库数据恢复正常,但 binlog缺失,主从不一致。
- 若只写 binlog,redo log 未提交时 crash,主库数据未更新,但 binlog却记录了操作,也会主从不一致。
所以,2PC 是保证事务一致性与主从一致性的关键机制。
总结
模块 | 类型 | 作用 |
---|---|---|
redo log | 物理日志 | 保证崩溃恢复,属于 InnoDB |
binlog | 逻辑日志 | 用于复制、备份、审计,属于 MySQL Server 层 |
两阶段提交 | 协调机制 | 保证两个日志一致,维护事务原子性与一致性 |