InnoDB
一、逻辑存储结构
二、架构
总结构
MySQL5.5 版本开始,默认使用InnoDB存储引擎,它擅长事务处理,具有崩溃恢复特性,在日常开发中使用非常广泛。 下面是InnoDB架构图,左侧为内存结构,右侧为磁盘结构。
2.1 内存结构
在左侧的内存结构中,主要分为这么四大块儿: Buffer Pool、Change Buffer、Adaptive Hash Index、Log Buffer。
1). Buffer Pool InnoDB存储引擎基于磁盘文件存储,访问物理硬盘和在内存中进行访问,速度相差很大,为了尽可能 弥补这两者之间的I/O效率的差值,就需要把经常使用的数据加载到缓冲池中,避免每次访问都进行磁 盘I/O。 在InnoDB的缓冲池中不仅缓存了索引页和数据页,还包含了undo页、插入缓存、自适应哈希索引以及 InnoDB的锁信息等等。
缓冲池 Buffer Pool,是主内存中的一个区域,里面可以缓存磁盘上经常操作的真实数据,在执行增 删改查操作时,先操作缓冲池中的数据(若缓冲池没有数据,则从磁盘加载并缓存),然后再以一定频 率刷新到磁盘,从而减少磁盘IO,加快处理速度。
缓冲池以Page页为单位,底层采用链表数据结构管理Page。 根据状态,将Page分为三种类型: ? free page:空闲page,未被使用。 ? clean page:被使用page,数据没有被修改过。 ? dirty page:脏页,被使用page,数据被修改过,也中数据与磁盘的数据产生了不一致。 在专用服务器上,通常将多达80%的物理内存分配给缓冲池 。参数设置: show variables like ‘innodb_buffer_pool_size’;
2). Change Buffer
Change Buffer,更改缓冲区(针对于非唯一二级索引页),在执行DML语句时,如果这些数据Page 没有在Buffer Pool中,不会直接操作磁盘,而会将数据变更存在更改缓冲区 Change Buffer 中,在未来数据被读取时,再将数据合并恢复到Buffer Pool中,再将合并后的数据刷新到磁盘中。
Change Buffer的意义是什么呢?
与聚集索引不同,二级索引通常是非唯一的,并且以相对随机的顺序插入二级索引。同样,删除和更新 可能会影响索引树中不相邻的二级索引页,如果每一次都操作磁盘,会造成大量的磁盘IO。有了 ChangeBuffer之后,我们可以在缓冲池中进行合并处理,减少磁盘IO。
3). Adaptive Hash Index
自适应hash索引,用于优化对Buffer Pool数据的查询。MySQL的innoDB引擎中虽然没有直接支持 hash索引,但是给我们提供了一个功能就是这个自适应hash索引。因为前面我们讲到过,hash索引在 进行等值匹配时,一般性能是要高于B+树的,因为hash索引一般只需要一次IO即可,而B+树,可能需 要几次匹配,所以hash索引的效率要高,但是hash索引又不适合做范围查询、模糊匹配等。
InnoDB存储引擎会监控对表上各索引页的查询,如果观察到在特定的条件下hash索引可以提升速度, 则建立hash索引,称之为自适应hash索引。
自适应哈希索引,无需人工干预,是系统根据情况自动完成。 参数: adaptive_hash_index
4). Log Buffer
Log Buffer:日志缓冲区,用来保存要写入到磁盘中的log日志数据(redo log 、undo log), 默认大小为 16MB,日志缓冲区的日志会定期刷新到磁盘中。如果需要更新、插入或删除许多行的事 务,增加日志缓冲区的大小可以节省磁盘 I/O。
参数: innodb_log_buffer_size:缓冲区大小 innodb_flush_log_at_trx_commit:日志刷新到磁盘时机,取值主要包含以下三个: 1: 日志在每次事务提交时写入并刷新到磁盘,默认值。 0: 每秒将日志写入并刷新到磁盘一次。 2: 日志在每次事务提交后写入,并每秒刷新到磁盘一次。
2.2 磁盘结构
①:System Tablespace:系统表空间是更改缓冲区的存储区域。如果表是在系统表空间而不是每个表文件或通用表空间中创建的,它也可能包含表和索引数据。(MySQL5.x版 本中还包含InnoDB数据字典、undolog等) 参数: innodb_ data_ file_ path
②:File-Per-Table Tablespaces:每个表的文件表空间包含单个InnoDB表的数据索引,并存储在文件系统.上的单个数据文件中。 参数: innodb_ file_ per_ table
默认是开启的;开启就意味着每张独立的表都有一个表空间,并不会再①中存放;
ibd文件每一个文件都是一个表空间文件,其中存放的就是这张表的表结构及表中的数据和索引;
③:General Tablespaces:通用表空间,需要自己通过CREATE TABLESPACE语法创建用表空间,在创建表时,可以指定该表空间。(了解)
创建:
create tablespace a_stu(随意别名) add datafile 'student.ibd' engine = innodb;
使用:
create table a(id int primary key auto increment,name varchar (10)) engine = innodb tablespacets a_stu;
④:Undo Tablespaces:撤销表空间,MySQL 实例在初始化时会自动创建两个默的undo表空间(初始大小16M),用于存储undo log日志。
⑤:Temporary Tablespaces:临时表空间。 InnoDB 使用会话临时表空间和全局临时表空间。存储用户创建的临时表等数据。
⑥:Doublewrite Buffer Files:双写缓冲区,innoDB引擎将数据页从Buffer Pool新到磁盘前,先将数据页写入双写缓冲区文件中,便于系统异常时恢复数据。
⑦:RedoLog:重做日志,是用来实现事务的持久性。该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo log) ,前者是在内存中,后者在磁盘中。当事务提交之后会把所有修改信息都会存到该日志中,用于在刷新脏页到磁盘时,发生错误时,进行数据恢复使用。
以循环方式写入重做日志文件,涉及两个文件:
**redo log:**它是循环写的,不会永久保存,每隔一段时间,清理之前没有用的redo log;因为redo log,当事务提前,也就没什么用了,因为它的作用是保证异常时, 继续数据恢复,从而保证事务的持久性;
2.3 后台线程
数据如何从内存写入磁盘的,就是这中间部分:后台线程
总结
整个体系结构就是:当我门业务操作的时候,那么会直接操作左边内存的缓冲区,如果缓冲区当中没有数据,会将右边磁盘当中的数据加载回来,然后再存储在缓存区当中;我门在增删改查的时候,都会去操作左边的缓冲区,然后缓冲区当中的数据会以一定的频率或者说一定的时机,要通过这组后台线程刷新到磁盘当中,然后再磁盘当中进行永久化保存(永久保存主要指的是我门表当中的数据和索引等相关信息,undo log和read log会被回收释放,不会永久保留);
三、事务原理
底层:
3.1 redo log
无redo log情况:
首先,客户端在进行事务操作时会发起请求去操作MySql服务器,在MySQL的InnoDB引擎中,分为内存结构和磁盘结构,磁盘结构里存放了很多ibd文件,内存结构中有一个很大的缓冲池,缓冲池中缓冲了我们很多数据页的信息。当客户端发起事务操作,在这次事务操作中,包含了多条update和delete语句,那么此时是怎么进行执行的呢? 首先,去操作缓冲区,在缓冲区中查找有没有对应操作的数据,如果没有,此次会通过后台线程把我们数据从磁盘中读取出来,然后缓存在缓冲区中;接下来就可以直接在缓冲区中执行客户发送的事务操作;此时,缓冲区中的数据就会发生变更,而磁盘中的数据没有变更,那么缓冲区中这个变更的数据页就叫脏页,会在一定时机,通过后台线程将其刷新至磁盘中,这个时候内存中的缓冲区和磁盘中数据就一致了。 但是脏页的数据并不是实时刷新的,而是一段时间或者一段频率刷新的,假如,脏页的数据往磁盘中刷新出错了,那么内存中的数据就没刷新到磁盘中。那么,事务都已经提交了并通知了用户成功,但最终在脏页刷新的时候失败了,那么持久性就没得到保障!
有redo log情况:
脏页数据从内存刷新到磁盘出现错误时,恢复用的,保证持久性。 为什么每次提交时要把redo log刷新到磁盘中? 提交事务时,不先将脏页直接刷新,先把redo log文件异步刷新到磁盘当中,由于是 log日志文件,日志文件都是追加的,此时就是顺序磁盘IO,效率远高于随机磁盘IO。 这种机制就是WAL(先写日志),日志是循环写,不会永久保留,这就是redo log。
3.2 undo log
四、MVCC
五、总结
|