Mysql InnoDB存储引擎
InnoDB的体系结构
分为三块,分别是后台线程,内存池,文件。
1.后台线程
后台线程主要作用是刷新内存池中的数据,保证缓冲池中数据都是最新的数据。
将缓冲池中的数据刷刷新到磁盘文件中,保证发生异常时候,发生缓冲池和磁盘数据不一致时能正常恢复。
后台线程分为:
-
Master Thread:核心线程,负责缓冲池数据刷回磁盘,脏页刷新,合并插入缓冲,UNDO页回收等。
每秒一次的工作:日志缓冲刷新到磁盘合并插入缓冲刷新100个InnoDB缓冲池中的脏页到磁盘即使事务还没有提交,InnoDB仍然会每秒将重做日志缓冲内容刷新到重做日志文件,所以即使是很大的事务也能快速提交。
每十秒一次的:
刷新100个脏页到磁盘合并至多5个插入缓冲将日志缓冲刷新到磁盘删除无用的Undo页
-
IO Thread:负责AIO的回调处理
第一是因为一个SQL的查询,可能需要读取磁盘中的多个索引页,AIO可以并行读取数据,提高读取的效率。
第二是可以进行IO合并操作,当读取的多个页是相邻的,可以合并为一个IO请求,提高IOPS -
Purge Thread:回收已经没有用的UNDO页(从Master Thread抽离)
-
Page Cleaner Thread:脏页刷新回磁盘(从Master Thread抽离)
2.内存缓冲池
缓冲池是主内存中的一个区域,里面可缓存磁盘上经常操作的真实数据,在执行增删改查操作时,先操作缓冲池中的数据(若缓冲池没有数据,则从磁盘加载并缓存),然后再以一定频率刷新到磁盘,从而减少磁盘IO,加快处理速度。
InnoDB将数据文件按页(每页16K)读入缓冲池,然后按最近最少使用算法(LRU)保留缓存数据,最后通过一定频率将脏页刷新到文件。
InnoDB内存数据对象:
1.页的读取:数据库读取页的时候,会先判断缓冲池中是否已经存在该页,如果存在,就直接使用缓冲池中的页,如果不存在,就从磁盘中进行读取。
2.页的修改:对于页的修改,也是先修改缓冲池中的页,然后再以一定的频率刷新到磁盘进行持久化。
如果数据在刷回磁盘前数据库异常了怎么办?
答案:根据Redo日志进行恢复。InnoDB会保证,在页修改时,Redo日志必须已经持久化到磁盘。
3.页的管理
InnoDB使用LRU来管理缓冲池中的页,LRU会把最新的数据插入到头部,淘汰掉尾部的数据。
InnoDB使用的LRU有一点不同的是,最新的数据会插入到中间的位置,这是为了避免一些冷门的大SQL需要扫描很多页,导致热点数据被刷掉。
修改缓冲(change buffer)
针对于非唯一二级索引页,在执行DML语句时,如果这些数据Page没有在Buffer Pool中,不会直接操作磁盘,而会将数据变更存在更改缓冲区(Change Buffer)中,在未来数据被读取中,再将数据合并恢复到Buffer Pool中,再将合并后的数据刷新到磁盘中。
修改缓冲需要满足两个条件
1.非唯一,因为唯一在插入时需要判断约束,无法缓冲
2.索引是非聚簇索引:InnoDB是用B+Tree的索引结构来存储数据的,非聚簇索引在存储结构上并不是连续的,这时候需要离散地读取非聚簇索引页,造成插入的性能下降
日志缓冲区
用来保存要写入到磁盘中的log日志(redo log,undo log),默认大小为16MB,日志缓冲区的日志会定期刷新到磁盘中,如果需要更新、插入或删除许多行的事务,增加日志缓冲区的大小可节省磁盘IO
3.文件
每张表通常都会对应多个文件,其中包括.ibd文件和.frm文件。
- ibd文件:数据文件,包含了表中的实际数据和索引信息。
- .frm文件:表结构定义文件,存储了表的元数据,如表的列名、数据类型、主键等。
- 日志文件:redo log/undo log/bin log