跳到主要内容

日志

慢查询日志 slow query log

重做日志 redo log

redo log 是 InnoDB 引擎特有的日志。

WAL 技术 write-ahead logging

核心是:先写日志,再写磁盘。

当有一条记录需要更新,InnoDB 引擎会先把记录写到 redo log 里面,并更新内存,这个时候就算更新完成了。同时,InnoDB 引擎会在系统空闲的时候, 将这个操作记录更新到磁盘里面。

redo log 使用 write pos 来标记当前记录的位置,checkpoint 标记当前要擦除的位置。

归档日志 binlog

binlog 与 redo log 的区别?

  • binlog 是 server 层日志,所有引擎都可以使用。
  • redo log 是物理日志,记录的是“在某个数据页上做了什么修改”; binlog 是逻辑日志,记录的是这个语句的原始逻辑。
  • redo log 是循环写的,空间固定会用完; binlog 是可以追加写入的。“追加写” 是指 binlog 文件写入一定大小后会切换到下一个,并不会覆盖 以前的日志。

两阶段提交

  • prepare
  • commit
  1. 事务的修改首先被记录到 redo log 中,并标记为 prepare 状态。此时,事务没有提交,redo log 保证了即使系统崩溃,更改也不会丢失。
  2. 一旦 redo log 成功记录,事务的修改就会被记录到 binlog 中。完成这一步后,事务在 redo log 中标记为已提交(commit)。

为什么要有 “两阶段提交” 呢?

  • 保证数据的一致性
  • 确保复制的准确性
  • 事务的原子性和持久性

回滚日志 undo log

InnoDB 中,为了回滚而记录的东西成为 undo log。

undo log 分为三种

  1. insert undo log
  2. update undo log
  3. delete undo log
    • 删除操作只是设置一下老记录中 DELETE_BIT 的隐式字段,并不是真正的将过时的记录删除。
    • 为了节省磁盘空间,InnoDB 由专门的 purge 线程来清理 DELETE_BIT 为 true 的记录。
    • purge 维护了自己的 read view, 如果某个记录的 DELETE_BIT 为 true,且 DB_TRX_ID 相对于 purge 线程的 read view 可见,那么这条记录 一定可以被安全清除的。

SQL 执行时添加 undo log 的过程

  1. 事务 A 向 person 表中插入了一条记录
nameageDB_ROW_ID(隐式主键)DB_TRX_ID(最后一次修改的事务ID)DB_ROLL_PTR(回滚指针)
Jerry241nullnull
  1. 事务 B 将 name 改为 Tom
  • 在事务 B 修改该行记录时,数据库会先对该行加排他锁
  • 然后把该行数据拷贝到 undo log 中,作为旧纪录
  • 拷贝完毕之后,修改该行记录为 Tom,并且修改隐藏字段的事务 ID 为当前事务 B 的ID,回滚指针指向拷贝到 undo log 的副本记录,表示我的上一个版本就是它。
  • 事务提交之后,释放锁。

事务 B

nameageDB_ROW_ID(隐式主键)DB_TRX_ID(最后一次修改的事务ID)DB_ROLL_PTR(回滚指针)
Tom2411ox11223344

undo 日志

nameageDB_ROW_ID(隐式主键)DB_TRX_ID(最后一次修改的事务ID)DB_ROLL_PTR(回滚指针)
Jerry241nullnull
  1. 事务 C 将 age 修改为 30
  • 在事务 C 修改该记录时,数据库对该数据加锁
  • 将数据拷贝到 undo log,此时发现 undo log 中有这条记录,那么最新的旧数据作为链表的表头,插在 undo log 中的该行记录最前面。
  • 修改 age 为 30,并且修改 DB_TRX_ID、DB_ROLL_PTR 字段
  • 事务提交,释放锁

事务 C

nameageDB_ROW_ID(隐式主键)DB_TRX_ID(最后一次修改的事务ID)DB_ROLL_PTR(回滚指针)
Tom3011ox12341234

undo 日志

nameageDB_ROW_ID(隐式主键)DB_TRX_ID(最后一次修改的事务ID)DB_ROLL_PTR(回滚指针)
Tom2411ox11223344
Jerry241nullnull

总结

事务对同一记录的修改,会导致该记录的 undo log 成为一条记录版本线性表(链表), undo log 的链首就是最新的旧记录,链尾就是最早的旧记录。