具体细节 请去掘金购买《MySQL 是怎样运行的:从根儿上理解 MySQL》
redo日志
row_id隐藏列赋值的方式
- 1.服务器会在内存中维护一个全局变量,每当向某个包含隐藏的row_id列的表中插入一条记录时,就会把该变量的值当作新记录的row_id列的值,并且把该变量自增1。
- 2.每当这个变量的值为256的倍数时,就会将该变量的值刷新到系统表空间的页号为7的页面中一个称之为Max Row ID的属性处
- 3.当系统启动时,会将上边提到的Max Row ID属性加载到内存中,将该值加上256之后赋值给我们前边提到的全局变量
逻辑日志
- 1.简单理解记录的是sql语句
物理日志
- 1.记录的是4元组数据,哪个表空间,哪个文件,哪个页,哪个偏移位置,插入的字节内容
逻辑物理日志
- 1.redo日志页面内的操作记录的是逻辑日志
- 2.redo日志页间的操作记录的是物理日志
- 3.binlog是逻辑日志
- 4.redo是逻辑物理日志,所以partial page时需要double write介入才能恢复数据
partial page
- 1.比如我们对一个页进行刷新操作,操作一般就断电了。
- 2.这个时候redo因为是页内是逻辑日志,只记录数据的逻辑,而原先的物理位置已经被占满了
- 3.因此只能完全的替换该页面,重新使用redo
redo日志解决了什么
- 1.磁盘的数据被load到bufferpool之后,如果我们修改buffer pool了,这些数据不会立马被刷入到磁盘,那么如何保证事务的持久性
- 2.如果修改了bufferpool页面数据就需要立即刷入磁盘,一个是太浪费(一个页有16kb,修个一个字节也刷16KB不合理),二个是随机IO刷起来慢(因为一个事务可能修改不同的页,这些页在物理上并不一定是连续的)
- 3.redo日志就是解决上述1和2的问题的。
redo日志的优点
- 1.占用的空间非常小:存储表空间ID、页号、偏移量以及需要更新的值
- 2.redo日志是顺序写入磁盘的
通用的redo日志格式
type
- 1.redo日志的类型
space ID
- 1.表空间ID。
page number
- 1.页号
data
- 1.该条redo日志的具体内容。
简单的redo日志类型
- 1.比如更新Max Row ID
MLOG_XBYTE(物理日志)
- 1.标识在页面的某个偏移量处写入了X字节的redo日志
- 2.多了一个offset,代表需要修改记录的起始位置
MLOG_WRITE_STRING(物理日志)
- 1.多了一个offset和len
- 2.len代表数据的长度
复杂一些的redo日志类型
- 1.一个语句可能会更新叶子节点,也有可能更新内节点,甚至于产生新的页面
- 2.还得需要更新Page Directory中的槽信息。
- 3.Page Header中的各种页面统计信息
- 4.还需要更新上一条记录的记录头信息中的next_record
- 5.把一条记录插入到一个页面时需要更改的地方非常多(多个页面)
- 6.因此复杂的redo日志处理包含物理层面的意思,也得包含逻辑层面的意思
- 7.物理层面看,这些日志都指明了对哪个表空间的哪个页进行了修改。
- 8.逻辑层面看,在系统奔溃重启时,并不能直接根据这些日志里的记载,将页面内的某个偏移量处恢复成某个数据,而是需要调用一些事先准备好的函数,执行完这些函数后才可以将页面恢复成系统奔溃前的样子。
MLOG_REC_INSERT
- 1.表示插入一条使用非紧凑行格式的记录时的redo日志类型。
- 2.Redundant是一种比较原始的行格式,它就是非紧凑的
MLOG_COMP_REC_INSERT
- 1.表示插入一条使用紧凑行格式的记录时的redo日志类型。
- 2.Compact、Dynamic以及Compressed行格式是较新的行格式,它们是紧凑的
- 3.日志结构比通用的日志额外多了以下字段
- 4.n_fields:记录该记录有多少个字段
- 5.n_uniques:在一条记录中,需要几个字段的值才能确保记录的唯一性
- 6.fieldX_len:第X个字段的占用的存储空间大小
- 7.offset:前一条记录的地址
- 8.end_seg_len:从该字段可以计算出当前记录总共占用的存储空间的大小
- 9.info bits:记录头信息的前4个比特位的值以及record_type的值
- 10.extra_size:记录额外信息占用的存储空间大小
- 11.mismatch index:未知作用
- 12.对于聚簇索引来说,n_uniques的值为主键的列数,对于其他二级索引来说,该值为索引列数+主键列数
MLOG_COMP_PAGE_CREATE
- 1.表示创建一个存储紧凑行格式记录的页面的redo日志类型。
MLOG_COMP_REC_DELETE
- 1.表示删除一条使用紧凑行格式记录的redo日志类型。
MLOG_COMP_LIST_START_DELETE
- 1.表示从某条给定记录开始删除页面中的一系列使用紧凑行格式记录的redo日志类型。
MLOG_COMP_LIST_END_DELETE
- 1.与MLOG_COMP_LIST_START_DELETE类型的redo日志呼应,表示删除一系列记录直到MLOG_COMP_LIST_END_DELETE类型的redo日志对应的记录为止。
MLOG_COMP_LIST_START_DELETE和MLOG_COMP_LIST_END_DELETE存在的意义
- 1.数据页中的记录是按照索引列大小的顺序组成单向链表的。有时候我们会有删除索引列的值在某个区间范围内的所有记录的需求,这时候如果我们每删除一条记录就写一条redo日志的话,效率可能有点低,
所以提出MLOG_COMP_LIST_START_DELETE和MLOG_COMP_LIST_END_DELETE类型的redo日志,可以很大程度上减少redo日志的条数
MLOG_ZIP_PAGE_COMPRESS
- 1.表示压缩一个数据页的redo日志类型。
redo日志格式小结
Mini-Transaction
- 1.以组的形式写入redo日志
- 2.在执行语句的过程中产生的redo日志被设计InnoDB的大叔人为的划分成了若干个不可分割的组
- 3.多个普通redo日志组成一个完成的redo日志,结尾是以一个type=MLOG_MULTI_REC_END结尾
- 4.当然只有一个redo日志也可以组成一个组,具体的看type的值
- 5.type字段是一个字节 8个bit,第一个bit代表该组是否是单一的redo,后面7位代表了redo的日志类型。
- 6.对底层页面中的一次原子访问的过程称之为一个Mini-Transaction--MTR
- 7.
一个事务包含若干个语句,一个语句对应若干个mtr,一个mtr包含若干个redo
redo日志的写入过程
redo log block
- 1.Innodb把mtr生成的redo日志都存放在大小为512字节的页(block)中,该页和表空间页有所区别--是共享表空间
- 2.block==log block header,log block body 和log block trailer
- 3.log block header和log block trailer存储的是一些管理信息,log block body存储的是redo
log block header
- 1.LOG_BLOCK_HDR_NO:每一个block都有一个大于0的唯一标号,本属性就表示该标号值。
- 2.LOG_BLOCK_HDR_DATA_LEN:表示block中已经使用了多少字节,初始值为12(因为log block body从第12个字节处开始)
- 3.LOG_BLOCK_FIRST_REC_GROUP:代表该block中第一个mtr生成的redo日志记录组的偏移量(其实也就是这个block里第一个mtr生成的第一条redo日志的偏移量)
- 4.LOG_BLOCK_CHECKPOINT_NO:表示所谓的checkpoint的序号
log block trailer
- 1.LOG_BLOCK_CHECKSUM:表示block的校验值,用于正确性校验
redo日志缓冲区
- 1.redo日志也需要缓冲区,其是在服务器启动时就向操作系统申请了一大片称之为redo log buffer的连续内存空间
- 2.这片内存空间被划分成若干个连续的redo log block
- 3.可以通过innodb_log_buffer_size来指定log buffer的大小
- 4.redo日志写入log buffer是顺序的,通过全局变量buf_free来指明后续的redo日志应该写入到log buffer中的哪个位置
- 5.并不是每生成一条redo日志,就将其插入到log buffer中,而是每个mtr运行过程中产生的日志先暂时存到一个地方,当该mtr结束的时候,将过程中产生的一组redo日志再全部复制到log buffer中
- 6.根据5的描述不同事务的mtr可能是交替写入log buffer的