作者简介:小明java问道之路,专注于研究 Java/ Liunx内核/ C++及汇编/计算机底层原理/源码,就职于大型金融公司后端高级工程师,擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。
热衷分享,喜欢原创~ 关注我会给你带来一些不一样的认知和成长。
CSDN博客专家/后端领域优质创作者/内容合伙人、InfoQ签约作者、阿里云专家/签约博主、51CTO专家
如果此文还不错的话,还请关注、点赞、收藏三连支持一下博主~
专栏系列(点击解锁)
学习路线(点击解锁)
知识定位
MySQL从入门到精通
MySQL从入门到精通
全面讲解MySQL知识与实战
计算机底层原理
深入理解计算机系统CSAPP
构件计算机体系和计算机思维
Linux内核源码解析
围绕Linux内核讲解计算机底层原理与并发
数据结构与企业题库精讲
数据结构与企业题库精讲
结合工作经验深入浅出,适合各层次,笔试面试算法题精讲
互联网架构分析与实战
企业系统架构分析实践与落地
行业前沿视角,专注于技术架构升级路线、架构实践
互联网企业防资损实践
金融公司的防资损方法论、代码与实践。
本文目录
本文导读
一、InnoDB存储结构之逻辑存储结构
1、表空间(Tablespace)
2、段(segment)
3、区(Extent)
4、页(Page)
5、行(Row)
二、InnoDB页结构解析
三、InnoDB行结构解析
1、Compact格式(压缩)
2、Redundant行记录格式(冗余)
3、Dynamic格式(动态压缩)
4、Compressed格式(压缩加强)
总结
在 InnoDB 存储引擎中,存储结构分为逻辑结构和物理结构,本文详细讲解Innodb的逻辑结构,表空间、段、区、页、行,并对页结构和行结构进行深入解析。
同时本文也是对前面文章的一个补充,结合使用效果更佳:《高性能高可用设计实战-索引篇》、《MVCC详解与MVCC实现原理》、《MySQL日志系统以及InnoDB背后的技术》。
在 InnoDB 存储引擎中,表记录按照主键顺序进行组织和存储。这种存储模式下的表称为索引组织表(index organized table)。每个表都有一个主键(列 rowId)。如果没有明确定义主键,InnoDB 存储引擎将自动创建一个6字节的主键。
InnoDB 存储引擎的所有创建的表,都逻辑存储在一个空间中,称为表空间(tablespace)。表空间由段(segment)、区(extent)、页(page)和行(row)组成,如下图所示:
表空间是InnoDB逻辑结构的顶层。所有数据都存储在表空间中。
默认情况下,InnoDB存储引擎有一个共享表空间 ibdata1(在数据目录下,用于存放undolog信息等等),即所有表的数据都存储在 ibdata1 空间中。通过 innodb_data_file_path 参数可以将多个文件定义为表空间。ibdata1文件位于默认数据目录中。
如果 Innodb 已启用,则 innodb_file_per_table 参数(默认为ON),每个表都有自己的独立表空间。
独立的表空间仅存储数据、索引和插入缓冲位图页。其他类型的数据(如undolog信息、插入缓冲索引页、系统事务信息和辅助写入缓冲)仍存储在原始共享表空间中。
-- 展示该表空间所对应的物理文件
ll ibdata1
# 查看是否每张表数据单独有一个表空间
show variables lisk 'innodb_file_per_table ';
表空间由多个段组成。公共段包括数据段、索引段和回滚段。
数据段:B+树的叶节点段(Leaf node segment)
索引段:B+树的非叶节点段(Non-Leaf node segment)
回滚段:撤消信息(undo log)
InnoDB存储引擎表是按索引组织(Index Organized)的,因此数据是索引,索引是数据,段由引擎本身管理。
区(extent)是由连续页组成的空间,每个区的大小固定都是1MB。
为了确保区中页的连续性,InonoDB存储引擎一次从磁盘请求4-5个区。默认情况下,InnoDB存储引擎的页大小为16KB,即一个区中应该有64个连续的页。
innodb_page_size 参数控制页的大小。默认大小为16KB。您可以设置4K和8K。此时,数据页不是压缩页。该区中的页数分别为256和128。但是无论页大小如何变化,区大小始终为1MB。
innodb_file_per_table 参数。每个表都有自己的表空间。当创建一个没有任何数据的表时,表空间大小为96KB(连续6个页 page)。为什么不是1MB(一个区的大小)?
原因是在每个段的开头,使用32个碎片页(fragment page)来存储数据,当它们用完时,将以区的形式应用新页。这样做的目的是通过在开始时为一些小表请求更少的空间来节省磁盘容量。以下代码是初始化大小。
页也称为块(block),是 InnoDB 磁盘管理的最小单位。静态参数 innodb_page_Size 控制页的大小。默认大小为16KB。可以设置4K和8K。
-- 查看页大小
SHOW VARIABLES LIKE 'innodb_page_size'
常见的页类型有:
数据页 (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)
InnoDB存储引擎是面向列的(row-oriented)按行存储。每个页上存储的行记录也是硬定义的,最多可存储16KB/2-200行(16*1024/2-200行,即7992行记录)。
每页至少存储2行记录,并与链表链接。否则,B+树的含义将丢失。
具有大数据(如大字符串、TEXT和BLOB对象)的行,记录使用采用行溢出数据存储。不同的行格式有不同的存储方法。
在行中,默认情况下有两个隐藏字段:Trx_Id:每次更改记录时,都会将相应的事务Id分配给Trx_Id。Roll_Pointer:每次更改索引记录时,旧版本都将写入撤消日志,隐藏列相当于一个指针,通过它可以在修改记录之前找到信息。
页(page),也称块(block),是InnoDB磁盘管理的最小单元。查看页大小SHOW VARIABLES LIKE 'innodb_page_size',参数 innodb_page_Size 控制页的大小。默认大小为16KB。可以设置4K和8K。
页类型为B-tree node的页存放的即是表中行的数据。
下图所示,是InnoDB存储引擎数据页结构。其中File Header、Page Header、File Trailer的大小固定,分别是38Byte、56Byte、8Byte,其他的大小都是动态。
File Header(文件头),用于记录页的头信息。
Page Header(页头),用于记录数据页的状态信息,共占56字节。
Infimum和Supremum Records(最小/最大虚拟行记录) ,在InnoDB引擎中,每个数据页都有一个虚拟行记录,用于限制用户记录的边界。Infimum记录小于页中的任何主键值;Supremum 记录的值大于页中的任何主键值。注意:这两个虚拟记录是在创建页时创建的,在任何情况下都不能删除。
User Records(用户记录),也称为行记录,实际上存储行记录的内容。InnoDB存储引擎表被索引,并且总是使用B+树来存储数据。
Page Directory(页目录),是记录的相对位置(页中的相对位置,而不是偏移量)。InnoDB中的一些记录指针称为槽(Slots)或目录槽(Directory Slots),并非每个都有槽。页目录是一个稀疏目录(sparse directory,即一个槽可以包含多个记录)。插槽中的记录按索引键值的顺序存储。目的是使用二进制搜索方法查找记录指针。页目录很好地解释了文件头中n的含义,因为有些记录不在页目录中。
Free Space(空闲空间),是指自由空间,它也是一个链表数据结构。删除记录后,该空间将添加到可用列表中。
File Trailer(文件结尾信息),文件尾用于检查页面是否完全写入磁盘(如磁盘损坏、停机等)。默认情况下,InnoDB引擎每次从磁盘读取页面时都会检查页面的完整性。innodb_checksums 参数控制是否启用页面完整性检查。默认情况下,它为ON。文件尾占用8Byte(字节),只有一个FIL_PAGE_END_LSN。前4字节是该页的checksum值,后4字节和File Header的FIL_PAGE_LSN相同。innodb_checksum_algorithm 参数控制测试校验和函数的算法。默认值为crc32。校验和通过指定函数比较一致性来检查页面的完整性。
在InnoDB 1.0.x之前,InnoDB存储引擎提供了Compact(压缩行)和Redundant(保留冗余)格式来存储行记录数据,这也是目前最常用的格式。
Redundant 格式以与先前版本兼容,在MySQL 5.1中,默认设置为Compact 格式。
可以使用命令SHOW TABLE STATUS LIKE'TABLE' 查看当前表使用的行格式,其中row_format属性表示当前使用的行记录结构的类型。
MySQL 5.0中引入了Compact(压缩)来高效存储数据。页中的数据行数越多,性能就越高。
MySQL-MVCC详解与MVCC实现原理
行格式的第一部分是非NULL可变长度字段长度列表,按列的相反顺序排列。长度为:如果列长度小于255Byte,则使用1Byte;如果列长度大于等于255Byte,则使用2Byte。
NULL标志位占2个字节。例如,NULL标志位的值06被转换为二进制00000110。值为1的位表示第二列和第三列的值为NULL(列值为NULL时,它不会占据任何位置。无论CHAR或VARCHAR类型如何,压缩格式的NULL值都不会占用任何存储空间)。
Redundant(冗余) 是MySQL 5.0之前InnoDB的行记录存储模式,MySQL 5.0支持Redundant,以兼容以前版本的页格式。
与压缩行记录格式不同,冗余行记录格式的第一部分是字段长度偏移列表,它也按照列顺序以相反的顺序放置。
如果列的长度小于255字节,则用1字节表示;如果大于255字节,则用2字节表示。第二部分是记录头(record header),它不同于压缩行记录格式。冗余行记录格式的记录头采用6字节(48位)。
Dynamic 动态格式是Compact的升级版本。大型VARCHAR、TEXT和BOLB类型采用完整的行溢出模式,20字节指针指向Off Page。
Compressed格式是Compact的升级版本。大型VARCHAR、TEXT和BOLB类型采用完整的行溢出模式,20字节指针指向OffPage。另一个功能是使用zlib算法压缩行数据,即压缩页。
在 InnoDB 存储引擎中,存储结构分为逻辑结构和物理结构,本文详细讲解Innodb的逻辑结构,表空间、段、区、页、行,并对页结构和行结构进行深入解析。
同时本文也是对前面文章的一个补充,结合使用效果更佳:《高性能高可用设计实战-索引篇》、《MVCC详解与MVCC实现原理》、《MySQL日志系统以及InnoDB背后的技术》。