文章目录
InnoDB的内存结构
Buffer Pool缓冲池
数据页和索引页
Page是InnoDB存储的最基本结构,也是InnoDB磁盘管理的最小单位,与数据库相关的所有内容都存在Page结构中。Page分为多种类型其中数据页与索引页是最关键的两种类型。
插入缓冲(Insert Buffer)
对于InnoDB插入时由于B+Tree的特性,按照主键顺序插入时效率是最高的。但当一张表存在非唯一非聚簇索引时,数据页还是顺序存放,但是叶子节点就需要离散的访问非聚簇页了,这样会造成插入效率下降。
为了解决这一问题,MySql设计了插入缓冲,对于非聚簇索引的插入,并不是立即插入到索引中,而是先判断插入的索引是否在缓冲池中,若存在直接插入,若不存在先放入缓冲池,然后再以一定得频率将缓冲池中的信息与索引叶子节点合并,这样可以将多个插入操作合并到一个操作中,大大提升了对非聚簇索引的插入性能。
自适应哈希索引(Adaptive Hash Index)
InnoDB会根据访问频率和模式,对热点页建立哈希索引,来提高检索效率,InnoDB会监控对表上各个索引页的查询,如果发现建立哈希索引会带来检索效率的提升,则建立哈希索引,所以叫自适应哈希索引。
建立自适应哈希索引有一个要求就是对一个页的连续访问模式必须是一样的,也就是说查询条件(where)必须一致,且必须是连续的。
锁信息(Lock Info)
存放所有的锁信息。
数据字典信息(Data Dictionary)
存放的是表结构,数据库名,表名,字段的数据类型,索引、视图字段信息,存储过程,触发器等信息。
Rodo Log Buffer 重做日志缓冲
当缓冲池中的页的版本比磁盘要新时(称作脏页,并不是脏数据的意思,只是这个版本比磁盘要新),数据库需要将新版本的页从缓冲池刷新到磁盘中称作数据落盘。
但是如果每一次变化就进行刷新,那么性能开销是非常大的,于是InnoDB采用了Write Ahead Log(WAL)策略,即当事务提交时,先写重做日志,然后再择时(check point检查点)将脏页写入磁盘。如果发生宕机导致数据丢失,就通过重做日志进行恢复(这也不能保证万无一失,也有可能数据还没有写入重做日志中,但是写入重做日志的频率肯定远远大于脏页落盘的频率)
同样InnoDB为了提高日志写入的效率,重做日志信息会先存放在重做日志缓冲当中,然后再按照一定得频率刷新到日志文件中(日志落盘)。重做日志缓冲不用设定的非常大,因为一般来说每一秒都会进行一次日志落盘。参数innodb_log_buffer_size来控制重做日志缓冲大小,默认8MB。
注意:日志文件是顺序写入,数据落盘是随机写,所以日志落盘效率大于日志落盘
innodb_flush_log_at_trx_commit是InnoDB调优的一个基础参数,定义了日志落盘的策略。
0:事务提交时不进行写入日志操作,。
1:数据提交时必须进行一次fsync(操作系统命令,fsync函数同步内存中所有已修改的文件数据到储存设备。即进行了数据落盘)。
2:表示提交时之写入OS BUFFER但不进行fsync操作。
这三个机制里面
- 0写入效率最高,但是由于提交时并没有理解写入磁盘,这样丧失了事务的持久性,所以数据安全最差。
- 1写入效率最低,但是数据安全最好。也只有1才能保证事务的持久性。
- 写入效率 与数据安全都是中等水平。
一般建议设成1。
Double Write 双写
双写由两部分组成,一部分是内存中2MB的双写缓冲,一部分是磁盘中连续128页加起来大小同样为2MB。在对缓冲池脏页进行刷新时并不是直接写入磁盘而是通过memcpy函数将藏也先复制到内存中的double write buffer,在分两次每次1MB顺序写入共享表空间物理磁盘上,然后没,马上通过fsync函数同步磁盘,避免操作系统缓冲写带来的问题。在完成double write页的写入后,再将double write buffer的页吸入哥哥表空间文件中。
如果操作系统在将页吸入磁盘的过程中发生了崩溃,在回复过程中,InnoDB存储引擎可以从共享表空间double write页找到该页的副本将其复制到表空间文件中,再应用重做日志。
Innodb的磁盘文件
innodb磁盘文件分为
- 系统表空间
- 用户表空间
- .frm表元数据文件
系统表空间(ibdata文件)
所有的表共享的表空间存放下面的内容
- 数据字典:存放数据库相关信息,也就是 InnoDB 表的元数据
- double write buffer: 双写缓存,防止页锻炼,解决部分写失败
- insert buffer :内存insert buffer数据,周期性写入表空间,防止意外宕机
- 回滚段
- undo空间
用户表空间
所有的表的元数据默认存放在系统表空间中,当my.ini中配置innodb_file_per_table = 1时,表的数据和索引的文件会存放在一个单独的文件中
该文件主要存放下列信息
- 表的数据和索引
- 表的结构
- undo空间
.frm文件
保存了每个表的元数据,包括表结构的定义等;
重做日志
redo日志,在mysql中默认以ib_logfile0,ib_logfile1名称存在,可以手工修改参数,调节开启几组日志来服务于当前mysql数据库,mysql采用顺序,循环写方式,每开启一个事务时,会把一些相关信息记录事务日志中(记录对数据文件数据修改的物理位置或叫做偏移量);
这个系列文件个数由参数innodb_log_files_in_group控制,若设置为4,则命名为ib_logfile0~3。
这些文件的写入是顺序、循环写的,logfile0写完从logfile1继续,logfile3写完则logfile0继续。
redo log只是记录所有innodb表数据的变化。
redo log只是记录正在执行中的dml以及ddl语句。
redo log可以作为异常down机或者介质故障后的数据恢复使用