该文章为知识总结的文章,如果是初学者,建议先从专栏学习:数据库专栏
文章目录
一、InnoDB存储引擎工作方式
- 将数据库文件按页(每页16k)读取到缓冲池,然后按照最近最少使用的算法(LRU)保留缓存数据。
- 如果数据发生更改,总是
先修改缓存池的页
(脏页),然后再保存在磁盘中
二、关键特性
1. 插入缓存
- 因为主键是表唯一标识,所以插入顺序按照主键递增(自增主键)的顺序插入。
- 因此,插入的聚集索引一般是顺序的,不需要对磁盘随机读取,所以速度很快。
- 但是一个表不止有聚集索引,索引的插入不再是顺序的
- 插入索引对于非聚集索引,不是一次性插入到索引页,先判断索引页是否在缓存池。如果在,直接插入;如果不在,先放入插入缓存,
将多个插入合并在一个中
(因为都是在一个索引页中),在根据磁盘IO情况更新到磁盘中。 索引必须是辅助索引,索引不是唯一的
- 默认最多占一半缓存池空间
缺点:
- 由于并没有及时把索引更新到磁盘中,如果数据库宕机,则
需要很多的时间恢复数据
2. 两次写
- 当数据库宕机时,数据库可能正在写一个页面,而这个页面只写了一部分,则称之为部分写失效,从而导致数据丢失
- 如果此时直接使用Undo日志,由于页出现了损坏,所以此时是无意义的
在执行Undo日志之前,先需要一个页副本用来恢复的没有写之前的状态,再进行重做。
- doublewrite由两部分组成:内存中的doublewrite buffer,物理磁盘共享表中的两个区
在缓冲池脏页刷新时,先将数据拷贝到内存中的doublewrite buffer,然后在写入物理磁盘共享表中的两个区,然后在更新磁盘数据
- 由于doublewrite是连续的,所以对其的IO操作时顺序写的,开销不大
3. 自适应哈希索引
- 哈希是一种查找办法,常用于join连接操作
- 会监控表上索引的查找,如果建立哈希索引可以提供速度,则建立哈希索引。
- 哈希索引通过缓存池中的B+数构造而来,因此建立速度很快
- 并不是整个表都需要建立哈希索引,InnoDB会根据访问的频率为某些页单独建立哈希索引
三、redo log、binlog和undo log
1. 什么是redo log?
-
redo log是InnoDB存储引擎层的日志,又称重做日志文件,用于记录事务操作的变化,记录的是数据修改之后的值,不管事务是否提交都会记录下来。在实例和介质失败(media failure)时,redo log文件就能派上用场,如数据库掉电,InnoDB存储引擎会使用redo log恢复到掉电前的时刻,以此来保证数据的完整性。
-
在一条更新语句进行执行的时候,InnoDB引擎会把更新记录写到redo log日志中,然后更新内存,此时算是语句执行完了,然后在空闲的时候或者是按照设定的更新策略将redo log中的内容更新到磁盘中,这里涉及到
WAL
即Write Ahead logging
技术,他的关键点是先写日志,再写磁盘。 -
有了redo log日志,那么在数据库进行异常重启的时候,可以根据redo log日志进行恢复,也就达到了
crash-safe
。 -
redo log日志的大小是固定的,即记录满了以后就从头循环写,并且会暂停当前的所有数据更改操作,先将redo log日志同步到磁盘中。
2. 什么是binlog?
- 可以作为数据恢复,在MySQL层面保证数据一致性的
- 属于逻辑日志,是以二进制的形式记录的是这个语句的原始逻辑
- 也可以用于主从之间保证数据一致性
3. redo log和binlog区别
-
redo log是属于innoDB层面,binlog属于MySQL Server层面的,这样在数据库用别的存储引擎时可以达到一致性的要求。
-
redo log是物理日志,记录该数据页更新的内容;binlog是逻辑日志,记录的是这个更新语句的原始逻辑
-
redo log是循环写,日志空间大小固定;binlog是追加写,是指一份写到一定大小的时候会更换下一个文件,不会覆盖。
-
binlog可以作为恢复数据使用,也可以用于主从复制搭建,redo log作为异常宕机或者介质故障后的数据恢复使用。
4. 回滚日志(undo log)
-
属于InnoDB层面保证事务的原子性
-
保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读
5. redo log和undo log的区别
- redo log是保证事务持久性的,undo log是保证事务原子性的
- undo log用于备份一个事务开始前的数据,不会影响原本的数据,都是先在备份中更改,最后写入磁盘
- redo log用于记录每一个数据更新的内容,用于在二次写中恢复破损的数据
6. 一条更新语句执行的顺序
update T set c=c+1 where ID=2;
- 执行器先找引擎取 ID=2 这一行。ID 是主键,引擎直接用树搜索找到这一行。如果 ID=2 这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。
- 执行器拿到引擎给的行数据,把这个值加上 1,比如原来是 N,现在就是 N+1,得到新的一行数据,再调用引擎接口写入这行新数据。
- 引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare 状态。然后告知执行器执行完成了,随时可以提交事务。
- 执行器生成这个操作的 binlog,并把 binlog 写入磁盘。
- 执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成提交(commit)状态,更新完成。