300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > InnoDB存储引擎的数据存储方式(存储模式)

InnoDB存储引擎的数据存储方式(存储模式)

时间:2024-02-05 10:55:48

相关推荐

InnoDB存储引擎的数据存储方式(存储模式)

逻辑存储结构

在InnoDB存储引擎中,所有数据都存放在表空间(tablespace)中,表空间由段(segment)、区(extent)、页(page)、行(Row)组成,它们的关系如下图:

表空间(tablespace)

在MySQL中,所有InnoDB存储引擎表中的数据都存储在表空间中。如果用户启用了innodb_file_per_table,那么每张表内的数据可以存储在一个单独的表空间文件(称为独立表空间文件)中,如果没有启用,那么数据都会存储在共享表空间文件中(默认情况下的ibdata0ibdata1文件)。在MySQL 5.7中,innodb_file_per_table默认是启用的:

mysql> show variables like 'innodb_file_per_table';+-----------------------+-------+| Variable_name | Value |+-----------------------+-------+| innodb_file_per_table | ON |+-----------------------+-------+1 row in set (0.05 sec)

独立表空间文件存放的只是这张表的数据、索引和插入缓冲Bitmap页。对于回滚信息、插入缓冲索引页、事务信息、二次写缓冲依然存放于共享表空间文件。

段(segment)

表空间由各个段组成,常见的段类型有:数据段、索引段、回滚段。

由于InnoDB表采用的是聚簇索引,所以数据段可以看成是B+树的叶子节点,索引段可以看成是B+树的非索引节点。

区(extend)

一个段由多个区组成,区由多个连续页组成,每个区的大小为1MB,默认情况下,每个页的大小为16KB:

mysql> show variables like 'innodb_page_size';+------------------+-------+| Variable_name | Value |+------------------+-------+| innodb_page_size | 16384 |+------------------+-------+1 row in set (0.05 sec)

即一个区中一共有64个连续页。用户可通过innodb_page_size参数设置每个页的大小。

默认情况下,用户在创建一张InnoDB表后,该表对应的独立表空间文件为96KB,在每个段开始时会先用32个碎片页来存放数据,使用完这32个页后才是64个连续页的申请。这么做是考虑到有些表的数据相对来说是比较少的,可以节省磁盘空间,因为申请64个页(即1个区)需要1MB空间。

页(page)

页是InnoDB磁盘管理的最小单位,默认大小为16KB。常见的页类型有:

数据页(B-tree Node)undo页(undo Log Page)系统页(System Page)事务数据页(Transaction system Page)插入缓冲位图页(Insert Buffer Bitmap)插入缓冲空闲列表页(Insert Buffer Free List)未压缩的二进制大对象页(Uncompressed BLOB Page)压缩的二进制大对象页(compressed BLOB Page

行(Row)

InnoDB存储引擎将数据按行进行存放,每个页最多存放7992行记录(16KB除以2~200),InnoDB存储引擎提供了CompactRedundantCompressedDynamic四种格式来存放行记录数据,用户可通过命令show table status like 'table_name'来查看该属性:

mysql> show table status like 'emp';+------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------+| Name | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time | Update_time | Check_time | Collation| Checksum | Create_options | Comment |+------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------+| emp | InnoDB |10 | Dynamic | 6 | 2730 | 16384 |0 | 0 | 0 | NULL | -08-10 21:07:05 | NULL | NULL | utf8mb4_general_ci | NULL|| |+------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------+1 row in set (0.08 sec)

其中Row_format就是行记录格式。下面我们来深入探讨InnoDB的行记录格式是如何实现的。

行记录格式

Compact

Compact行记录格式是在MySQL 5.0引入的,设计目标是高效地存储数据,每行数据的存储方式如下:

变长字段长度列表

Compact行记录格式首部是一个非NULL的变长字段长度列表,按照列的顺序逆序放置,若列的长度小于255字节,则用1字节表示,若大于255个字节,用2字节表示。变长字段长度列表最大只能为2字节,因此VARCHAR类型理论最大长度限制为65535字节)。变长字段长度列表的实际占用大小由变长列的数量及其属性决定。

NULL标志位(1字节)

NULL标志位记录了该行数据是否有NULL值,有则用1表示,该标志位占用1个字节

记录头信息(5字节)

列数据

最后的部分就是存储每个列的数据,需要注意的是NULL不占用任何空间,即NULL除了占有NULL标志位以外实际存储不占有任何空间。此外,除了实际存储数据的列以外,还存在两个隐藏列:事务ID列(6字节)、回滚指针列(7字节)。如果没有定义主键,每行还会自动添加一个6字节的rowid列。

行溢出的处理

对于TEXTBLOB或者长度比较大的VARCHAR这种存储的数据量较大的列,因为超出了页的大小(16KB),也就是发生了行溢出。

Compact/Redundant两种行记录格式下,InnoDB会将溢出的数据存储在Uncompress BLOB类型的页中,没有溢出的数据部分依旧保存在数据页(B-Tree Node)中。

B-tree Node负责保存一行数据前768字节,之后记录了一个偏移量,指向行溢出页。

因为InnoDB是采用B+树进行索引组织的,所以每个页中至少应当有两行记录(不然每个页存储一行数据就是链表结构了),因此如果页中只能存放一条记录,那么InnoDB会将行数据存放到溢出页中。

Dynamic / Compressed

Dynamic / Compressed文件格式统称为Barracuda文件格式,这两种格式采用了完全行溢出的处理方式:数据页中只存储20个字节的指针,实际数据存放在Off Page中:

Compressed行记录还会使用zlib算法对大长度数据进行压缩,能够节省存储空间。

数据页(B-tree Node)结构

InnoDB数据页由7个部分组成

File Header(文件头),占用38字节Page Header(页头),占用56字节Infimum/Supremum RecordsUser Records(用户记录 / 行记录)Free Space(空闲空间)Page Directory(页目录)File Trailer(文件结尾信息),占用8字节

File HeaderPage HeaderFile Trailer大小是固定的,用来标记该页的的一些信息。User RecordsFree SpacePage Directory为实际的行记录存储空间,大小是动态的。

File Header组成结构

File Header负责记录页的头信息,占用38字节:

FIL_PAGE_SPACE_OR_CHECKSUM(4字节):页的checksum的值FIL_PAGE_OFFSET(4字节):页的偏移值,即该页在表空间的位置FIL_PAGE_PREV(4字节):当前页的上一个页(B+树的叶子节点通过双向列表连接在一起)FIL_PAGE_NEXT(4字节):当前页的下一个页FIL_PAGE_LSN(8字节):代表该页最后被修改的日志序列位置FIL_PAGE_TYPE(2字节):页的类型。当值为0x45BF代表当前页是数据页,0x000A表示是BLOB页,0x0003表示是索引节点…FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID(4字节):当前页属于哪个表空间

Page Header组成结构
PAGE_N_DIR_SLOTS(2字节):在页目录(Page Directory)中的槽(Slot)数。PAGE_HEAP_TOP(2字节):堆中第一个记录的指针PAGE_N_HEAP(2字节):堆中记录数,第15位表示行记录格式PAGE_FREE(2字节):指向可重用空间的首指针PAGE_GARBAGE(2字节):已删除记录的字节数PAGE_LAST_INSERT(2字节):最后插入记录的位置PAGE_DIRECTION(2字节):最后插入的方向PAGE_N_DIRECTION(2字节):一个方向连续插入记录的数量PAGE_N_RECS(2字节):该页中记录的数量PAGE_MAX_TRX_ID(8字节):修改当前页的最大事务IDPAGE_LEVEL(2字节):当前页在索引树(B+ tree)位置PAGE_INDEX_ID(8字节):索引ID,表示当前页属于哪一个索引PAGE_BTR_SEG_LEAF(10字节):B+树数据页非叶节点所在段的segment headerPAGE_BTR_SEG_TOP(10字节):B+树数据页所在段的segment header
Infimum / Supremum Record

在InnoDB引擎中每个页都有两个虚拟行记录用来限定记录的边界Infimum记录了比该页任何主键值都要小的值,Supremum Record记录了比任何可能大的主键值还要大的值,这两个字段在页创建时被创建并且不会被删除,占用大小和行记录格式相关。Infimum在行记录首部,Supremum Record在行记录尾部。

User Record / Free Space

User Record实际存储行记录的内容

Free Space即空闲空间,也是采用“链表”的方式存储,当前页一条记录被删除后,该空间就会被加入到空闲链表中。

Page Directory

Page Directory(页目录)存放了记录的相对位置(不是偏移量),页目录里面的这些记录指针称之为Slots(槽)。对于InnoDB来说,并不是每个记录都拥有一个唯一的槽,因为每个槽里面可能包含了多条记录。Slots中的记录按照索引键值存放,这样可以利用二叉查找快速找到记录的指针。

需要注意的是,B+树本身并不能找到具体的一条记录,只能找到该记录所在的页。数据库通过磁盘IO把页读入到内存,然后再通过页目录进行二叉查找,二叉查找在内存中的速度很快,一般会忽略这部分的时间。

File Trailer

为了检测页是否完整写入了磁盘,InnoDB存储引擎的页中设置了File Trailer部分。

File Trailer占用8个字节,前4个字节表示该页的checksum值,最后4个字节和FileHeader中的FIL_PAGE_LSN相同。通过与这个值进行比较,来保证当前页是完整的。默认情况下InnoDB每从磁盘中读取页就会检验这个页的完整性。

参考资料

《MySQL技术内幕(InnoDB存储引擎)》

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。