###MySQL逻辑架构
redo log & bin log
MySQL的每次数据更改都不会立即写入磁盘的,因为这是一个大量IO的过程,耗时耗力,一个可取的操作时我先把当前的操作记录在日志里,等到夜深人静操作系统空闲的时候,在通过日志把相关的修改持久化。
所以,机智的MySQL设计者们就提出了一个叫做WAL(write ahead logging)的技术。
每当对数据库进行修改操作时,会先在redo log中添加一行记录“需要在哪个数据页上做什么修改”,并且把这行记录的状态设置为prepare状态,等到事务提交后,再把redo log中的这行记录的状态设置为commit.
redo log记录方式
redo log是InnoDB所有的,它的大小是固定的,可以通过特定参数来配置日志文件的数量和每个日志文件的大小。
它采用循环写的方式,如下图:
其中write pos表示当前打算写的位置,write pos和check point之间的空间表示空闲空间,因为是循环写,所以必然存在一个写满的问题,写满了,就要擦除,然后继续写,所以它是不能保存过去的所有时刻的状态。
有了这个redo log,就可以保证数据库异常重启后,我们仍然可以根据redo log里面的记录进行恢复,我们把这个能力叫做crash-safe.
那么问题来了,既然都有了redo log,为什么还要bin log呢?
根据上述分析,我们知道:
- redo log是InnoDB引擎特有的,其他引擎没有
- redo log容量有限,所以不会保存太多的历史记录。
基于上述两条,我们又有了bin log, 那它们有什么区别呢?
- bin log是属于server层的,所以它对于所有存储引擎都能用
- bin log是通过追加方式写入的,所以旧的记录不会被擦除
- redo log记录的是物理修改,比如某个页面的某个值修改为啥,而bin log记录的逻辑操作,你可以认为它记录了一条SQL语句
有了这两个日志后,这两份日志需要保证逻辑一致(我也不知道为啥,先记着吧),而这个保证是通过一个叫做两阶段提交的方式来实现的:
它的大意是这样的,当有一个数据库的修改时,先将修改后的值放到内存,然后在redo log里面记录一哈,此时的状态是prepare, 然后在bin log里面再记录一哈,最后提交事务,将redo log里面的状态设置为commit. 等到夜深人静的时候,就可以通过redo里面这些状态为commit的字段来修改数据库了。
change buffer
今天学习了change buffer, 简单来说,change buffer是用给普通索引的,对于频繁的更新或者插入操作,唯一索引需要把对应数据页读入内存检查唯一性,这势必会增加IO开销。而对普通索引来说,则没有必要检查唯一性,所以遇到更新或者插入操作,不着急把数据页读入内存进行更新,而是可以先把要进行的操作读入一个change buffer中,等后面啥时候机缘巧合了把对应数据页读进来和change buffer merge一下。