MySQL:简介 Ubuntu 安装 MySQL MySQL:官方文档地址 MySQL:DDL、DQL、DML、DCL的含义 MySQL:Mac 中启动 关闭 MySQL 服务 MySQL:有哪些好用的管理工具? MySQL:命令行工具 mycli MySQL:CHAR类型 MySQL:VARCHAR类型 MySQL:整型数字 MySQL:datetime 类型 MySQL:时间戳 MySQL:创建和删除数据库 MySQL:切换和查看数据库 MySQL:创建和删除表 MySQL:在表中增加、删除、修改列 MySQL:创建和删除主键 MySQL:使用 rename 修改表名 MySQL:修改自增主键id的类型 MySQL:如何创建一个相同的表 MySQL:修改表的字符编码 MySQL:增删查改 MySQL:插入数据 MySQL:插入多行数据 MySQL:使用 insert set 插入数据 MySQL:大小写和反引号 MySQL:字符串类型值的大小写 MySQL:SQL注释 MySQL:不要使用utf8 MySQL:NULL的判等 MySQL:InnoDB存储引擎的限制 MySQL:if和case的使用 MySQL:使用 load data 快速导入数据 MySQL:使用 select into outfile 导出数据 MySQL:查询和设置 sql_mode MySQL:严格模式 MySQL:NOT NULL 字段不插入数据,会发生什么? MySQL:无符号整数列插入负数会发生什么? MySQL:关于 null 的那些事 MySQL:大表行数查询 MySQL:自动生成创建时间、更新时间;自动更新更新时间 MySQL:insert ignore MySQL:字符集排序规则 MySQL:如果连续更新一个字段两次,结果是? MySQL:字符串转数字 MySQL:尾部空格 MySQL:添加和删除索引 MySQL:唯一索引与NULL MySQL:唯一索引的单列长度限制 MySQL:InnoDB 索引 MySQL:字符集排序规则对唯一索引的影响 MySQL:唯一索引冲突消耗主键 ID MySQL 使用 index hint 指定索引:ignore index、force index、use index MySQL:查看客户端连接信息 MySQL:查看表的状态 show table status MySQL:如何治理连接数 ? MySQL:如何监控和处理慢查询与长事务 ? MySQL:自定义函数 MySQL:now() 函数 MySQL:unix_timestamp() 函数 MySQL:from_unixtime() 函数 MySQL:version() 函数 MySQL:current_timestamp() 函数 MySQL:cast 函数 MySQL:convert 函数 MySQL:使用 greatest、least 函数获取行最大值、最小值 MySQL:使用 group_concat 函数连接多行数据为一个字符串 MySQL:获取版本号 MySQL:Java 类型映射 MySQL下创建只能有一行记录的table 关于MySQL的字符集 理解数据库中的undo日志、redo日志、检查点 ubuntu下源码安装MySQL MySQL:JOIN解惑 如何快速更新数据库中的百万条数据

理解数据库中的undo日志、redo日志、检查点


#MySQL


2014-6-18

本文内容准确性可能有问题

数据库存放数据的文件,本文称其为data file。 数据库的内容在内存里是有缓存的,这里命名为db buffer。某次操作,我们取了数据库某表格中的数据,这个数据会在内存中缓存一些时间。对这个数据的修改在开始时候也只是修改在内存中的内容。当db buffer已满或者遇到其他的情况,这些数据会写入data file。

undo,redo

日志在内存里也是有缓存的,这里将其叫做log buffer。磁盘上的日志文件称为log file。log file一般是追加内容,可以认为是顺序写,顺序写的磁盘IO开销要小于随机写。

Undo日志记录某数据被修改前的值,可以用来在事务失败时进行rollback;Redo日志记录某数据块被修改后的值,可以用来恢复未写入data file的已成功事务更新的数据。下面的示例来自于杨传辉《大数据分布式存储系统 原理解析与架构实践》,略作改动。

例如某一事务的事务序号为T1,其对数据X进行修改,设X的原值是5,修改后的值为15,那么Undo日志为<T1, X, 5>,Redo日志为<T1, X, 15>

也有把undo和redo结合起来的做法,叫做Undo/Redo日志,在这个例子中Undo/Redo日志为<T1, X, 5, 15>

当用户生成一个数据库事务时,undo log buffer会记录被修改的数据的原始值,redo会记录被修改的数据的更新后的值。

redo日志应首先持久化在磁盘上,然后事务的操作结果才写入db buffer,(此时,内存中的数据和data file对应的数据不同,我们认为内存中的数据是脏数据),db buffer再选择合适的时机将数据持久化到data file中。这种顺序可以保证在需要故障恢复时恢复最后的修改操作。先持久化日志的策略叫做Write Ahead Log,即预写日志。

在很多系统中,undo日志并非存到日志文件中,而是存放在数据库内部的一个特殊段中。本文中就把这些存储行为都泛化为undo日志存储到undo log file中。

对于某事务T,在log file的记录中必须开始于事务开始标记(比如“start T”),结束于事务结束标记(比如“end T”、"commit T")。在系统恢复时,如果在log file中某个事务没有事务结束标记,那么需要对这个事务进行undo操作,如果有事务结束标记,则redo。

在db buffer中的内容写入磁盘数据库文件之前,应当把log buffer的内容写入磁盘日志文件。

有一个问题,redo log buffer和undo log buffer存储的事务数量是多少,是按照什么规则将日志写入log file?如果存储的事务数量都是1个,也就意味着是将日志立即刷入磁盘,那么数据的一致性很好保证。在执行事T时,突然断电,如果未对磁盘上的redo log file发生追加操作,可以把这个事务T看做未成功。如果redo log file被修改,则认为事务是成功了,重启数据库使用redo log恢复数据到db buffer和 data file即可。

如果存储多个的话,其实也挺好解释的。就是db buffer写入data file之前,先把日志写入log file。这种方式可以减少磁盘IO,增加吞吐量。不过,这种方式适用于一致性要求不高的场合。因为如果出现断电等系统故障,log buffer、db buffer中的完成的事务会丢失。以转账为例,如果用户的转账事务在这种情况下丢失了,这意味着在系统恢复后用户需要重新转账。

检查点checkpoint

checkpoint是为了定期将db buffer的内容刷新到data file。当遇到内存不足、db buffer已满等情况时,需要将db buffer中的内容/部分内容(特别是脏数据)转储到data file中。在转储时,会记录checkpoint发生的”时刻“。在故障回复时候,只需要redo/undo最近的一次checkpoint之后的操作。

幂等性问题

在日志文件中的操作记录应该具有幂等性。幂等性,就是说同一个操作执行多次和执行一次,结果是一样的。例如,5*1 = 5*1*1*1,所以对5的乘1操作具有幂等性。日志文件在故障恢复中,可能会回放多次(比如第一次回放到一半时系统断电了,不得不再重新回放),如果操作记录不满足幂等性,会造成数据错误。

资料

What Is Undo?
Redo log
Oracle学习笔记:Redo日志(重做日志)的作用
数据库日志文件-- undo log 、redo log、 undo/redo log
undo log与redo log原理分析
Oracle redo与undo浅析
RedoLog Checkpoint 和 SCN关系
mysql dba系统学习(10)innodb引擎的redo log日志的原理
2.4 Checkpoint技术
MySQL Innodb日志机制深入分析
《MySQL技术内幕:InnoDB存储引擎(第2版)》



( 本文完 )