问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

InnoDB引擎详解:存储结构、事务原理与MVCC机制

创作时间:
作者:
@小白创作中心

InnoDB引擎详解:存储结构、事务原理与MVCC机制

引用
CSDN
1.
https://m.blog.csdn.net/weixin_61943305/article/details/145948479

InnoDB是MySQL中最常用的一种存储引擎,它以其事务处理能力和崩溃恢复特性在日常开发中被广泛使用。本文将详细介绍InnoDB的逻辑存储结构、事务原理以及MVCC(多版本并发控制)机制,帮助读者深入理解InnoDB的工作原理。

1. 逻辑存储结构

MySQL 5.5版本开始,默认使用InnoDB存储引擎,它擅长事务处理,具有崩溃恢复特性,在日常开发中使用非常广泛。下面是InnoDB架构图,左侧为内存结构,右侧为磁盘结构。

内存架构

  • Buffer Pool(缓冲池):缓冲池是主内存中的一个区域,里面可以缓存磁盘上经常操作的真实数据,在执行增删改查操作时,先操作缓冲池中的数据(若缓冲池没有数据,则从磁盘加载并缓存),然后再以一定频率刷新到磁盘,从而减少磁盘IO,加快处理速度。缓冲池以Page页为单位,底层采用链表数据结构管理Page。根据状态,将Page分为三种类型:

  • free page:空闲page,未被使用。

  • clean page:被使用page,数据没有被修改过。

  • dirty page:脏页,被使用page,数据被修改过,也中数据与磁盘的数据产生了不一致。

  • Change Buffer(更改缓冲区):更改缓冲区(针对于非唯一二级索引页),在执行DML语句时,如果这些数据Page没有在Buffer Pool中,不会直接操作磁盘,而会将数据变更存在更改缓冲区Change Buffer 中,在未来数据被读取时,再将数据合并恢复到BufferPool中,再将合并后的数据剧新到磁盘中。

    Change Buffer的意义是什么?
    与聚集索引不同,二级紫引通常是非唯一的,并且以相对随机的顺序插入二级紫引。同样,删除和更新可能会影响索引树中不相邻的二级索引页,如果每一次都操作磁盘,会造成大量的磁盘io。有了ChangeBuffer之后,我们可以在缓冲池中进行合并处理,减少磁盘io。

  • Adaptive Hash index(自适应hash索引):用于优化对BufferPool数据的查询。InnoDB存储引擎会监控对表上各索引页的查询,如果观察到hash索引可以提升速度,则建立hash索引,称之为自适应hash索引。自适应哈希索索引,无需人工干预,是系统根据情况自动完成,

    参数:adaptive hash index

  • Log Buffer(日志缓冲区):用来保存要写入到盛盘中的l0g日志数据(redo log、undo log),默认大小为 16MB,日志缓冲区的日志会定期剧新到磁盘中。如果需要更新、插入或删除许多行的事务,增加日志缓冲区的大小可以节省磁盘I/0。

    参数:

  • innodb_log_buffer_size:缓冲区大小

  • innodb_flush_log_at_trx_commit:日志刷新到磁盘时机

  • 1:日志在每次事务提交时写入并刷新到磁盘

  • 0:每秒将日志写入井剧新到磁盘一次。

  • 2:日志在每次事务提交后写入,并每秒刷新到磁盘一次

磁盘结构

  • System Tablespace(系统表空间):系统表空间是更改缓冲区的存储区域。如果表是在系统表空间而不是每个表文件或通用表空间中创建的,它也可能包含表和索引数据。(在MySQL5.x版本中还包含InnoDB数据字典、undolog等)。

    参数:innodb_data_file_path

  • File-Per-Table Tablespaces(每个表的文件表空间):每个表的文件表空间包含单个InnoDB表的数据和索引,并存储在文件系统上的单个致据文件中。

    参数:innodb_file_phr_table

  • GeneralTablespaces(通用表空间):通用表空间,需要通过CREATE TABLESPACE 语法创建通用表空间,在创建表时,可以指定该表空间。

  • Undo Tablespaces(微销表空间):MySQL实例在初始化时会自动创建两个默认的undo表空间(初始大小16M),用于存储undolog日志。

  • TemporaryTablespaces(临时表空间):InnoDB使用会话临时表空间和全局临时表空间。存储用户创建的临时表等数据。

  • Doublewrite Buffer Files(双写缓冲区):innoDB引擎将数据页从Buffer Pool刷新到磁盘前,先将数据页写入双写缓冲区文件中,便于系统异常时恢复数据。

  • Redo Log(重做日志):重做日志,是用来实现事务的持久性。该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo log),前者是在内存中,后者在磁盘中。当事务提交之后会把所有修改信息都会存到该日志中,用于在刷新脏页到磁盘时,发生错误时,进行数据恢复使用。

后台线程

当业务在操作时会直接操作缓冲区,缓冲区中没有数据的时候,会将磁盘区的数据加载回来,存储到缓存区中,在进行增删改查的时候,会操纵缓冲区,缓冲区中的数据会与一定的时机通过后台线程刷新到磁盘区中,并永久化的保存下来。

2. 事务原理

事务

事务 是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么全部成功,要么全部失败。

特性

  1. 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
  2. 一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态。
  3. 隔离性(lsolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
  4. 持久性(Durability):事务旦提交或回滚,它对数据库中的数据的改变就是永久的。

并发事务问题

问题
描述
脏读
一个事务读到另一个事务还没有提交的数据
不可重复读
一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读
幻读
一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了幻觉

事务隔离级别

隔离级别
脏读
不可重复读
幻读
Read uncommitted(读未提交)
Read committer(读已提交)
×
Repeatable Read(默认,可重复读)
×
×
Serializable(串行化)
×
×
×

redo log(保证持久性)

重做日志,记录的是事务提交时数据页的物理修改,是用来实现事务的持久性。该日志文件出两部分组成:重做日志缓冲(redolog bufer)以及重做日志文件(redolog file),前者是在内存中,后者在磁盘中。当事务提交之后会把所有修改信息都存到该日志文件中,用于在刷新脏页到磁盘,发生错误时,进行数据恢复使用。

undo log(解决原子性)

回滚日志,用于记录数据被修改前的信息,作用包含两个:提供回滚 和 MVCC(多版本并发控制)undoloq和redo log记录物理日志不一样,它是逻辑日志。可以认为当delete一条记录时,undo(og中会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相反的update记录。当执行rolback时,就可以从undolog中的逻辑记录读取到相应的内容并进行回滚。

Undolog销毁:undolog在事务执行时产生,事务提交时,并不会立即删除undolog,因为这些日志可能还用于MVCC。

Undolog存储:undolog采用段的方式进行管理和记录,存放在前面介绍的 rollback segment 回滚段中,内部包含1024个undolog segment.

3. MVCC

1. 当前读

读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如:select … lock in share mode(共享锁),select… for update、update、insert、delete(排他锁)都是一种当前读。

2. 快照读

简单的select(不加锁)就是快照读,快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。

  • Read Committed:每次select,都生成一个快照读。
  • Repeatable Read:开启事务后第一个select语句才是快照读的地方。
  • Serializable:快照读会退化为当前读。

3. MVCC

全称 Multi-Version Concurrency Control,多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,快照读为MySQL实现MVCC提供了一个非阻塞读功能。MVCC的具体实现,还需要依赖于数据库记录中的三个隐式字段、undol0q日志、readView。

mvcc隐藏字段

隐藏字段
含义
DB_TRX_ID
最近修改事务id,记录插入这条事务或最后一次修改该事务的事务id。
DB_POLL_PTR
回滚指针,指向这条记录的上一个版本,用于配合undo log,指向上一个版本。
DB_ROW_ID
隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段。

undolog日志

回滚日志,在insert、update、delete的时候产生的便于数据回滚的日志。

  • 当insert的时候,产生的undolog日志只在回滚时需要,在事务提交后,可被立即除。
  • 而update、delete的时候,产生的undolog日志不仅在回滚时需要,在快照读时也需要,不会立即被删除

undolog版本链

readview

ReadView(读视图)是 快照读 SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id。

ReadView中包含了四个核心字段:

字段
含义
m_ids
当前活跃的事务id集合
min_trx_id
最小活跃事务id
max_trx_id
预分配事务id,当前最大事务id+1
creator_trx_id
readview创建者的事务id

trx id:代表是当前事务ID,

  1. trx id == creator_trx_id 可以访问该版本
  2. trx id<min_trx_id 可以访问该版本 成立,说明数据是当前这个事务更改的。 成立,说明数据已经提交了。版本链数据访问规则
  3. trx _id>max_trx _id? 不可以访问该版本 成立,说明该事务是在Readview生成后才开启。
  4. min _trx_id <= trx _id <= max_trx_id? 如果trx id不在m ids中是可以访问该版本的 成立,说明数据已经提交,

不同的隔离级别,生成ReadView的时机不同:

  • READ COMMITTED:在事务中每一次执行快照读时生成Readview。
  • REPEATABLE READ:仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。

原理分析

一 RC隔离级别下。每一IC执行快照读的时候生成ReadView。
在并发事务执行的时候,会产生一个版本链,版本链的数据访问规则就是右边的四个规则,在第一个快照读的时候,各个属性和数值在图中已经标出来了,第一条记录的trx ID是4,4不等于5往下看,4大于3,继续往第三条规则,4小于6继续看第四条规则,第四条规则不符合,所以说明第一次查找的快照读不是该条记录,继续比对下一条记录。下一条的记录的trx ID是三,逐一比对发现都不符合,继续比对下一条下一条记录的trx ID是二经过比对,符合条件二可以访问该版本,就将trx ID是二的记录返回。

RR隔离级别下,仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。
我的理解是:因为时可重复读,所以在同一事务中每次读到的数据都是相同的,所以后续的快照读直接复用第一次即可实现。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号