结构图
内存
Buffer Pool 数据缓冲
对于数据的操作,不是每次都直接操作磁盘,因为磁盘的速度太慢了。 InnoDB使用了一种缓冲池的技术,也就是把磁盘读到的页放到一块内存区域里面。这个内存区域就叫Buffer Pool
- InnoDB操作数据有一个最小的逻辑单位,叫做页(索引页和数据页,占16KB),Buffer Pool缓存的是就是他们。
- 读取页先判断是不是在缓冲池里面,如果是,就直接读取,不用再次访问磁盘。
- 修改数据先修改缓冲池里面的页。
- InnoDB里面有专门的后台线程把Buffer Pool的数据写入到磁盘
- 默认大小是128M
- LRU算法来管理缓冲池
Change Pool写缓冲
当需要更新一个数据页时,如果数据页在BufferPool中存在,那么就直接更新好了。否则的话就需要从磁盘加载到内存,再对内存的数据页进行操作。也就是说,如果没有命中缓冲池,至少要产生一次磁盘IO;如果这个数据页不是唯一索引,不存在数据重复的情况,也就不需要从磁盘加载索引页判断数据是不是重复(唯一性检查)。这种情况下可以先把修改记录在Change Buffer中,从而提升更新语句(Insert、Delete、Update)的执行速度
- 把 Change Buffer 记录到数据页的操作叫做 merge
- 什么时候发生 merge?在访问这个数据页的时候,或者通过后台线程、或者数据库shut down、redo log写满时触发
- change buffer 用的是 buffer pool 里的内存,可以通过参数 innodb_change_buffer_max_size 来动态设置
- change buffer 只限于用在普通索引的场景下,而不适用于唯一索引。在实际使用中,普通索引和 change buffer 的配合使用,对于数据量大的表的更新优化还是很明显的
- 对于写多读少的业务来说,页面在写完以后马上被访问到的概率比较小,此时 change buffer 的使用效果最好。这种业务模型常见的就是账单类、日志类的系统
Adaptive Hash Index
对于一些热点数据页,InnoDB会自动建立自适应Hash索引,也就是在B+Tree索引基础上建立Hash索引,这个过程对于客户端是不可控制的,隐式的
redo log(重做日志)
如果在内存中(Buffer Pool)把数据改了,还没来得及落磁盘,而此时的数据库挂了怎么办?如果每个请求都需要将数据立马落磁盘之后,那速度会很慢,MySQL可能也顶不住
- 记录的是“在某个数据页上做了什么修改”。当有一条记录需要更新的时候,InnoDB 引擎就会先把记录写到 redo log里面,并更新内存,这个时候更新就算完成了。同时,InnoDB 引擎会在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候做,然后才删除log
- redo log 是循环写的,空间固定会用完,此时停止更新,强制刷新log到磁盘。这种日志和磁盘配合的整个过程,其实就是 MySQL 里的 WAL 技术(Write-Ahead Logging),它的关键点就是先写日志,再写磁盘
- 当然redo log也不是每一次都直接写入磁盘,在Buffer Pool里面有一块内存区域(Log Buffer)专门用来保存即将要写入日志文件的数据,默认16M,它一样可以节省磁盘IO
- 刷盘时间:
0 延时写 :logbuffer 将每秒一次地写入 logfile 中,并且 logfile 的 flush 操作同时进行。 该模式下,在事务提交的时候,不会主动触发写入磁盘的操作。
1(默认,实时写,实时刷) :每次事务提交时 MySQL 都会把 logbuffer 的数据写入 logfile,并且刷到磁盘 中去。
2(实时写,延 迟刷):每次事务提交时 MySQL 都会把 logbuffer 的数据写入 logfile。但是 flush 操 作并不会同时进行。该模式下,MySQL 会每秒执行一次 flush 操作。 - 作用:保证即使数据库发生异常重启,之前提交的记录都不会丢
- 如一条更新操作,如果内存数据页中已经存在该数据则直接更新数据页,redoLog会增加一条日志记录;如果不在内存数据页中,则在Change Buffer中记录一条要往某数据页更新的log,同时redoLog也会新增一条Change Bufer要往某数据页更新的log,redolog记录普通数据页的改动和changebuffer的改动
磁盘
system tablespace 系统表空间
由内部系统表组成,存储表和索引的元数据
双写缓冲区
- InnoDB的页和操作系统的页大小不一致,InnoDB页大小一般为16K,操作系统页大小为4K,InnoDB的页写入到磁盘时,一个页需要分4次写
- 如果宕机导致页本身损坏,用redo log来做崩溃恢复是没有意义的。所以在对于应用redolog之前,需要一个页的副本。如果出现了写入失效,就用页的副本来还原这个页,然后再应用redolog。这个页的副本就是double write,InnoDB的双写技术。通过它实现了数据页的可靠性。
- 跟redo log 一样,double write 由两部分组成,一部分是内存的double write,一个部分是磁盘上的doublewrite。因为doublewrite是顺序写入的,不会带来很大的开销
file-per-table tablespaces 独占表空间
开启后,则每张表会开辟一个表空间,存放表的索引和数据
general tablespaces 通用表空间
可以创建一个通用的表空间,用来存储不同数据库的表
temporary tablespaces 临时表空间
存储临时表的数据,包括用户创建的临时表,和磁盘的内部临时表
Redo log
undo log tablespace
undolog(撤销日志或回滚日志)记录了事务发生之前的数据状态(不包括select) ,如果修改数据时出现异常,可以用undo log来实现回滚操作(保持原子性)。
和redo log的交互
- 事务开始,从内存或磁盘取到这条数据,返回给Server 的执行器;
- 执行器修改这一行数据的值为penyuyan;
- 记录name=qingshan到undo log;
- 调用存储引擎接口,在内存(Buffer Pool)中修改 name=penyuyan;
- 记录name=penyuyan到redo log;
- 事务提交。
存储
每张InnoDB 的表有两个文件(.frm和.ibd)