数据库的ACID属性
Atomicity:原子性,以事物transact为最小单位,事物中的所有操作,要么都执行完,要么都不执行,不存在一部分操作执行,另一部分操作不执行的情况。
Consistency:一致性,在事物开始和事物完成后,数据库的完整性限制不会改变。
Isolation:隔离性,同一个数据库中同时并发执行多个事务,事物之间的操作不会相互影响。
Durability:持久性,事物完成之后,事物所作的操作会持久存在于数据库中。
Redo log 和undo log
Redo log:由DML(insert delete update)操作,引起的页面变化,都需要记录到redo log中,大部分为物理日志
在页面修改完成之后,在脏数据由cache写入到磁盘之前,会写入redo日志中。
日志先行,日志会先写入到磁盘中,数据后写入
聚簇索引/二级索引/undo页面的修改,均需要记录在redo日志中
Redo log是啥?官方文档解释如下:
Redo log是一个基于磁盘的数据格式,在数据库灾难恢复过程中,用于恢复未完成的事物,修复数据的。在正常的操作过程中,redo log将来自于SQL 语句或者其他API调用的请求,转化为数据表中的变化,当对数据的改变操作还未完成之前,遭遇了意外的停机,那这些变化会在数据库启动初始化的过程中进行replay重演,这个重演的过程,是在接受client请求之前,就会完成。
默认情况下,redo log在磁盘上的体现,一般是ib_logfile0和ib_logfile1两个文件,mysql以循环的方式,写这两个文件,在redo log中的数据,是以记录变化为编码,这些日志数据,也就体现了数据的变化,在log中的一段内容,就体现了一个已经增加的LSN增量。
在mysql的配置文件中,innodb_log_file_size设置了redo log文件的大小,innodb_log_file_in_group设置了日志文件的个数,这些设置必须重启才能生效,当innodb检测到设置的大小和当前的文件大小不一致时,会设置一个检查点,然后关闭该日志文件,删除旧文件,创建一个设置大小的日志文件,开始写入日志。
Redo log刷盘的组提交
和其他所有兼容ACID模型的数据库引擎一样,innodb数据引擎也是会在事物提交之前,先将redo log文件刷盘,而且innodb还使用了一种组提交机制,同时将多个事务的redo log刷到磁盘中,避免一个事物一个提交,通过该组提交机制,一次日志刷盘操作,会将同时进行的多个事务的redo log提交,提高了中断效率。
Undo log:由DML 操作导致的数据记录变化,均需要将变化前的镜像,写入到undo log中,是一种逻辑日志。
undo log是啥?官方文档解释如下:
undo log是一组undo log记录的集合,这些undo log记录是关于某个事物的,一个undo log记录中包含了描述如何将最后的更新回退到集群索引记录的信息,如果有某一个事物需要去使用原始数据(比如在一个一致性的读事物中),这些原始没有被修改的数据,就会通过undo log记录进行恢复。Undo log存在于undo log段中,undo log段中包含了回滚段,而回滚段存在于系统表空间、临时表空间和回滚表空间中。
Innodb支持128个回滚段,其中有32个是为临时表的事物操作预留的,每一个更新临时表的事物(不包含只读事物)会被分配2个回滚段,一个是启用了redo的回滚段,另一个是没有启用redo的回滚段。只读事物只会分配一个没有启用redo的回滚段,因为只读事物是只允许修改临时表的。
剩下的96个回滚段,每一个都支持1023个一致性数据修改事物,所以能够支持近似于96K的一致性数据修改事物,96K的限制是假设事物不会去修改临时表,如果所有的数据修改事物都修改了临时表,这个大小大约是32K。
既然DML操作,会引起redo log和undo log的变化,具体进行分析一下。
Insert 插入操作:
Insert插入操作,不会对原有数据产生影响,只是新产生一条记录和对应的索引,以前的记录和索引不会被修改,所以对undo log的要求不高,但是对redo log的要求就比较高了,用于replay,就需要整条插入的所有信息。
Undo log:记录insert插入记录的主键值
Redo log:记录日志操作页面(space_id,page_no)、完整的插入记录、系统列等
Delete删除操作
Delete删除操作是要从当前的库或者表中删除一部分已经存在的记录,如果在删除过程中出现了数据库的crash,在recovery过程中需要再次进行删除操作,而recovery中的replay利用的就是redo log,所以redo log中需要记录删除的具体信息,比如主键等关键信息;而在undo log中需要记录的信息就会更多了,因为有可能在执行删除事物之前,存在一个一致性的读事物,需要读取当前被删除的这些记录,所以这些删除的记录的原始数据,是要存放在undo log中的;另外,由于读查询是会使用到索引等信息,所以这些索引信息,也是要存放在undo log中的。所以综上:
Redo log:记录日志操作页面、删除记录的系统列,记录在页面中的位置,同时记录undo page的修改
Undo log:
-
Delete操作在innodb中为delete mark操作,并不是真的删除数据,只是将记录标记为delete
-
记录当前删除记录的系统列
-
记录当前删除记录的主键
-
记录当前删除记录的所有索引
Update操作
Update的操作分为三种情况,对于不同的操作情况,redo log和undo log中记录的信息也是不一样的。
Section 1:未修改索引,修改的属性列长度不变
在这种update场景中,只是对非索引列的值进行了修改,并未修改该列的长度,所以在redo log中,会进行定点的update,会记录的是update log;而在undo log中,需要记录的是update操作的系统列、操作记录的主键、操作记录该列的原值,如果该update列中包含二级索引,二级索引的原值,也需要记录到undo log中。综上:
Redo log:记录update redo log,如果更新列中包含二级索引,则需要对二级索引进行delete mark操作,然后重新insert一条新的二级索引;同时对undo 页面的修改,同步也要写入到redo log中。
Undo log:记录update的系统列、操作记录的主键、操作记录该列的原值。如果该update列中包含二级索引,二级索引的原值,也需要记录到undo log中
Section 2:未修改索引,修改了属性列长度
这种update场景和section 1中的场景类似,唯一的区别是属性列长度发生了变化,这中变化,在undo log中记录的信息,和section 1中的信息形同,而redo log中记录的信息会发生变化,这个时候记录的不再是定点的update,应该是先delete原始的信息,然后insert一条信息。
undo log:记录信息和section 1中的undo log信息相同
redo log:不能定点的update了,会记录delete+insert redo log
section 3:修改索引列值
在数据库中,修改某条记录的索引列值,实际上的操作是将该记录delete,然后重新插入一条新的记录,然后生成索引,更新索引表。在这一连串的操作过程中,redo log实际上是要记录一个delete和一个insert的redo log,而undo log上是要记录原始的记录(delete操作)和insert的操作记录。
LSN:log sequence number
日志序列号,递增产生,一个LSN可以唯一标识一个redo log,其中有一个叫checkpoint LSN,用来标识数据库crash的redo 起始点,LSN和日志文件位置意义对应。