MySQL高级(二):一条更新语句是如何执行的
执行步骤
1. 解析 SQL 语句
MySQL 首先会解析你输入的 UPDATE
语句。解析器会检查语法是否正确,并将 SQL 语句转化为内部的数据结构(通常是语法树)。
示例 SQL 语句:
UPDATE employees SET salary = 5000 WHERE department = 'Sales';
2. 查询优化
MySQL 会根据查询优化器来决定如何高效执行该更新操作。优化器会生成不同的执行计划并选择最优的执行路径。这一步对于 UPDATE
语句通常意味着决定如何检索要更新的记录,以及使用哪些索引(如果有的话)。
- 如果
WHERE
子句中有索引,优化器会考虑使用索引来提高查询速度。 - 如果没有索引,可能会进行全表扫描。
3. 确定要更新的记录
在执行 UPDATE
操作时,MySQL 会根据 WHERE
子句来确定哪些记录需要被更新。在这个过程中,MySQL 会:
- 使用索引(如果有的话)查找符合条件的记录。
- 如果没有索引,则会全表扫描,逐行检查。
4. 锁定涉及的行
为了保证数据一致性,MySQL 会在对数据进行更新时使用锁机制,防止其他事务修改同一行数据。这可以是行级锁或表级锁,具体取决于存储引擎(例如 InnoDB)以及事务的隔离级别。
- InnoDB 存储引擎:通常使用行级锁。
- MyISAM 存储引擎:使用表级锁。
5. 执行更新
MySQL 会在符合条件的记录上执行更新操作。它会计算新的字段值,并将其写入数据页。这个步骤涉及以下几个方面:
- 修改数据页:更新操作会修改数据页中的内容。
- 记录日志:MySQL 会将更新操作记录到事务日志(如
redo log
或binlog
),以便后续的事务恢复或复制。
6. 提交或回滚事务
如果更新操作是在事务中进行的:
- 如果事务提交,更新会被永久保存。
- 如果事务回滚,所有更新会被撤销。
在 InnoDB 存储引擎中,更新操作是通过“日志”的方式确保可恢复性的,即使系统崩溃也可以恢复到一致的状态。
7. 提交更新(对于非事务型存储引擎)
对于非事务型存储引擎(如 MyISAM),MySQL 会立即将更新写入磁盘,不需要提交事务。
redo log 和 binlog
在 MySQL 中,redo log 和 binlog 都是用于事务日志记录的重要机制。
redo log
Redo Log(重做日志)是 MySQL InnoDB 存储引擎使用的一种日志类型,它主要用于确保事务的持久性(即 ACID 中的 Durability)和故障恢复。Redo Log 记录了所有对数据库的修改操作,这些修改是为了能够在系统崩溃后,保证数据的一致性和恢复。
特点
- 事务日志:Redo log 记录的是事务执行过程中对数据页的修改操作,确保即使数据库发生崩溃,也可以通过 redo log 恢复数据。
- 物理日志:Redo log 记录的是物理层面的变化,即实际的数据修改操作(如页的更新、插入或删除行等),并不像 binlog 记录的是 SQL 语句。
- 日志缓冲区:InnoDB 会将事务修改的日志先写入到 日志缓冲区(log buffer)中,再定期将这些日志刷写到 redo log 文件。
- 重做:在系统崩溃时,通过 redo log,MySQL 可以重做(redo)未提交的事务,以确保数据不会丢失(即持久性)。
- 写入顺序:Redo log 是顺序写入的,通常比数据库数据页的更新要快得多。
工作流程
- 事务修改数据时,InnoDB 会首先将修改的日志写入 redo log buffer。
- 每隔一定时间(或者当 buffer 满时),Redo log 会刷新到磁盘的 redo log 文件(通常是
ib_logfile0
和ib_logfile1
)。 - 在崩溃恢复时,MySQL 使用 redo log 中的记录来重做所有未完全持久化的数据修改,确保数据一致性。
例子
- 你执行
UPDATE employees SET salary = 5000 WHERE id = 1;
,修改了数据库中的某个数据页。 - 这个修改操作会先被记录到 redo log 中,而不会立即更新磁盘上的数据页(InnoDB 会将其缓存在内存中)。
- 如果系统崩溃,在恢复时,InnoDB 会通过 redo log 重做未完成的操作。
binlog
Binlog(二进制日志)是 MySQL 用来记录所有对数据库执行的修改操作的日志,主要用于数据的备份、恢复和主从复制。Binlog 记录的是 逻辑层面的操作(SQL 语句或者事件),而不是直接的物理数据修改。
特点
- 逻辑日志:Binlog 记录的是 SQL 语句(如
INSERT
、UPDATE
、DELETE
)或者逻辑事件(如表结构变更)执行的结果,而不是物理的页面修改。 - 主从复制:Binlog 是 MySQL 主从复制的核心,主服务器的所有修改操作(如
INSERT
、UPDATE
等)会被记录在 binlog 中,然后从服务器会从 binlog 中读取这些事件并执行相应的 SQL 语句来保持数据同步。 - 持久性和一致性:Binlog 是一个逻辑日志,用来记录数据变更的操作。它也可以用于数据恢复和备份。
- 不同的格式:Binlog 支持三种格式:
- STATEMENT:记录 SQL 语句。
- ROW:记录每一行数据的具体变化。
- MIXED:混合模式,结合了 STATEMENT 和 ROW 两种模式。
工作流程
- 在执行一个更新操作时(例如
UPDATE employees SET salary = 5000 WHERE department = 'Sales';
),该 SQL 语句会被记录到 binlog 中。 - Binlog 事件会被顺序写入磁盘中的二进制文件,通常是
mysql-bin.000001
这种格式。 - 在主从复制中,从服务器会读取 binlog 中的事件,并通过执行这些事件来同步数据。
例子
- 你执行
INSERT INTO employees (id, name, salary) VALUES (1, 'Alice', 5000);
,该语句会被记录到 binlog 中。 - 主服务器上的所有修改都会写入 binlog,从服务器会读取并执行这些语句,保持与主服务器的数据一致性。
区别
特性 | Redo Log | Binlog |
---|---|---|
目的 | 用于事务持久化和崩溃恢复 | 用于数据备份、恢复和主从复制 |
记录内容 | 物理修改操作(数据页变化) | 逻辑操作(SQL 语句或者事件) |
存储位置 | 存储在 InnoDB 存储引擎的 redo log 文件中 | 存储在 MySQL 的 binlog 文件中 |
更新频率 | 持续且高频的写入,写入日志缓冲区 | 以事件为单位记录,通常是较低频率的写入 |
恢复方式 | 在崩溃恢复时,重做未提交的事务,保证数据一致性 | 可以用于主从复制,也可用于基于事件的恢复 |
是否跨服务器复制 | 不参与主从复制,只与本地数据库相关 | 是的,支持主从复制和基于 binlog 的数据恢复 |
总结
- Redo Log:是 InnoDB 用来确保事务持久性和恢复操作的一种机制,记录了对数据页的物理修改。它用于系统崩溃后的恢复。
- Binlog:记录了数据库的逻辑变化(SQL 语句或事件),用于数据的备份、恢复以及主从复制。
两者各自担任不同的角色,Redo Log 主要用于事务的持久性和崩溃恢复,而 Binlog 则用于数据复制、备份和恢复。
总结
- 解析:解析 SQL 语句。
- 优化:选择最佳执行计划。
- 查找记录:根据
WHERE
条件查找符合更新条件的记录。 - 锁定行:锁定符合条件的记录,防止其他事务并发修改。
- 更新数据:执行实际的更新操作,修改数据页,并记录日志。
- 事务处理:事务提交或回滚(如果是事务型存储引擎)。
影响性能的因素
- 索引:
WHERE
子句中的字段是否有索引。 - 表的大小:表中数据量越大,更新操作的成本越高,特别是没有合适索引时需要全表扫描。
- 事务隔离级别:事务的隔离级别(如
READ COMMITTED
、SERIALIZABLE
)也会影响锁的粒度及更新的性能。 - 表的存储引擎:不同的存储引擎(InnoDB vs MyISAM)会影响更新的行为,尤其是在事务和锁的处理上。