MySQL(十四)InnoDB引擎详细讲解(逻辑存储结构、架构、事务原理、MVCC)
InnoDB引擎1.逻辑存储结构表空间ibd文件一个mysql实例可以对应多个表空间用于存储记录、索引等数据。段分为数据段Leaf node segment、索引段Non-leaf node segment、回滚段Rollback segmentInnoDB 是索引组织表数据段就是B树的叶子节点 索引段即为B树的非叶子节点。段用来管理多个Extent区。区表空间的单元结构每个区的大小为1M。 默认情况下 InnoDB存储引擎页大小为16K 即一个区中一共有64个连续的页。页是InnoDB 存储引擎磁盘管理的最小单元每个页的大小默认为 16KB。为了保证页的连续性InnoDB 存储引擎每次从磁盘申请 4-5 个区。行InnoDB 存储引擎数据是按行进行存放的。Trx_id每次对某条记录进行改动时都会把对应的事务id赋值给trx_id隐藏列。Roll_pointer每次对某条引记录进行改动时都会把旧的版本写入到undo日志中然后这个隐藏列就相当于一个指针可以通过它来找到该记录修改前的信息。2.架构MySQL5.5 版本开始默认使用InnoDB存储引擎它擅长事务处理具有崩溃恢复特性在日常开发中使用非常广泛。下面是InnoDB架构图左侧为内存结构右侧为磁盘结构2.1 内存架构adaptive_hash_index控制是否启用自适应哈希索引ON表示开启OFF表示关闭默认值是ON具体操作参考系统变量。2.2 磁盘结构innodb_data_file_path用于定义InnoDB的系统表空间System Tablespace的文件路径、大小和属性。innodb_file_per_table控制InnoDB是否为每个表创建独立的表空间文件ON表示每个表都有自己的表空间文件OFF表示所有表的数据和索引存储在系统表空间中默认值是ON。通用表空间将多个表的数据存储在一个共享的文件中方便管理和维护。创建通用表空间文件CREATE TABLESPACE tablespace_name ADD DATAFILE file_name.ibd [FILE_BLOCK_SIZE value] [ENGINE [] InnoDB]; tablespace_name通用表空间的名称 file_name.ibd表空间文件的路径和名称要确保指定的文件路径是MySQL可访问的并且有足够的权限 FILE_BLOCK_SIZE可选参数指定表空间的文件块大小通常与表的页大小一致必须与表的页大小一致例如16K ENGINE指定存储引擎默认为 InnoDB。创建表时指定表空间CREATE TABLE ...[TABLESPACE tablespace_name]; tablespace_name指定表存储的通用表空间名称将现有表移动到通用表空间ALTER TABLE table_name TABLESPACE tablespace_name;删除通用表空间DROP TABLESPACE tablespace_name;2.3 后台线程3.事务原理特性原理分类图原子性通过undo log日志实现持久性通过redo log日志实现一致性通过undo log和redo log两个日志实现隔离性通过锁和MVCC实现3.1 redo log重做日志记录的是事务提交时数据页的物理修改是用来实现事务的持久性。该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo log file)前者是在内存中后者在磁盘中。当事务提交之后会把所有修改信息都存到该日志文件中,用于在刷新脏页到磁盘,发生错误时,进行数据恢复使用。Buffer Pool在产生脏页数据的时候会先将数据存储到 redo log buffer 再存储到 redo log 中进行磁盘持久化存储在内存出现异常比如突然断电时通过redo log中持久化的数据进行回滚。过程如下图当用户执行UPDATE或DELETE操作时数据页会被加载到内存的Buffer Pool中进行修改同时生成Redo Log记录并暂存于Redo Log Buffer中。事务提交时Redo Log Buffer中的日志会先写入磁盘的Redo Log文件ib_logfile0/1确保事务的持久性而数据页的修改则通过后台线程异步刷入磁盘的表空间文件.ibd。这种WAL机制保证了即使系统崩溃也能通过Redo Log恢复未刷盘的数据变更从而确保数据的一致性和持久性。问题数据为什么要通过redolog写入ibd表空间文件而不是直接从Buffer Pool直接刷新到磁盘ibd文件答Buffer Pool 刷盘是随机写数据页在磁盘上的位置是分散的、随机的每次刷盘都需要寻址性能较低。Redo Log 是顺序写每次写入都是追加到日志文件的末尾性能非常高。3.2 undo log回滚日志用于记录数据被修改前的信息作用包含提供回滚 和 MVCC(多版本并发控制)。undo log 和 redo log 记录物理日志不一样它是逻辑日志。可以认为当 delete 一条记录时undo log中会记录一条对应的insert记录反之亦然当 update 一条记录时它记录一条对应相反的 update 记录。当执行 rollback 时就可以从 undo log 中的逻辑记录读取到相应的内容并进行回滚。Undo log 销毁undo log 在事务执行时产生事务提交时并不会立即删除undol0g因为这些日志可能还用于 MVCCUndo log 存储undo log 采用段的方式进行管理和记录存放在前面介绍的 rollback segment 回滚段中内部包含1024个 undo log segment3.3 MVCC3.3.1 基本概念当前读读取的是记录的最新版本读取时还要保证其他并发事务不能修改当前记录会对读取的记录进行加锁。对于我们日常的操作如:select…lock in share mode(共享锁)select… for update、update、insert、delete(排他锁)都是一种当前读快照读简单的select(不加锁)就是快照读快照读读取的是记录数据的可见版本有可能是历史数据不加锁是非阻塞读Read committed每次select都生成一个快照读Repeatable Read开启事务后第一个select语句才是快照读的地方Serializable快照读会退化为当前读MVCC全称 Multi-Version Concurrency Control多版本并发控制。指维护一个数据的多个版本使得读写操作没有冲突快照读为MySQL实现MVCC提供了一个非阻塞读功能。MVCC的具体实现还需要依赖于数据库记录中的三个隐式字段、undo log日志、read View3.3.2 记录中的隐藏字段每一张创建的表都有两个或三个隐藏字段DB_TRX_ID、DB_ROOL_PRT、DB_ROW_ID表没有主键时存在3.3.3 undo log回滚日志在insert、update、delete的时候产生的便于数据回滚的日志。当insert的时候产生的undoloq日志只在回滚时需要在事务提交后可被立即删除。当update、delete的时候产生的undo log日志不仅在回滚时需要在快照读时也需要不会立即被删除。那么何时删除当所有依赖于该undo log的快照读取操作结束后undo log才会被删除。这意味着如果有一个事务正在进行快照读取并且依赖于某个undo log那么这个undo log会一直保留直到该事务结束。undo log版本链3.3.4 readviewReadView(读视图)是 快照读 SQL执行时MVCC提取数据的依据记录并维护系统当前活跃的事务(未提交的)idReadView中包含了四个核心字段字段含义m_ids当前活跃的事务ID集合min_trx_id最小活跃事务IDmax_trx_id预分配事务ID当前最大事务ID1因为事务ID是自增的creator_trx_idReadView创建者的事务IDREAD COMMITTED针对事务5的两条查询语句第一条查询语句记录一次ReadView读视图拿着当前事务id即DB_TRX_ID4根据版本链数据访问规则依次判断判断到第4条发现trx_id4在集合m_ids中在链表结构找到下一个DB_TRX_ID3再次进行判断发现3仍然在集合m_ids中再次在链表结构找到下一个DB_TRX_ID2发现满足第2条规则所以查询到0x00002指向的记录id: 30, age: 3, name: A30;事务5的第二条查询语句重新记录一次ReadView读视图然后根据新的ReadView读视图重新判断直到找到满足版本链数据访问规则的一条版本记录为止所以两次查询结果不一定一致REPEATBLE READ查询过程和READ COMMITTED相同只是事务5的第二条查询语句不会重新生成ReadView读视图会复用第一条查询语句的ReadView读视图所以两次查询的结果一致