3. InnoDB的表结构

专栏地址:

MySQL系列文章专栏



1. 概述

InnoDB表是索引组织表,整张表是一颗按照主键构造的B+树,在叶子节点保存了整行数据(如果没有行溢出的话)。如果没有指定主键,InnoDB会首先尝试将非空唯一索引作为主键,其次自动创建一个6字节大小的主键。

2. 逻辑存储结构

表(Tablespace)-> 段(segment)-> 区(extent)-> 页(page)

从逻辑上来看,InnoDB表的所有数据被放在一个表空间中,表空间又由段、区、页组成。

在这里插入图片描述

2.1 表空间

默认情况下,InnoDB存储引擎有一个共享表空间ibdata1,存放所有的数据。若开启了参数innodb_file_per_table,则每张表的数据,比如表数据、索引和插入缓存Bitmap页等可以单独放在自己的表空间中,其它类型的数据,如undo log、double write buffer、change buffer、事务信息等数据仍然存放在原来的表空间内。

2.2 段

表空间由段组成,常见的段有数据段、索引段、回滚段等。数据段为B+树的叶子节点,索引段为非叶子节点。

2.3 区

区是由连续的页组成,其大小使用为1MB,在默认情况下,InnoDB页的大小为16KB,即一个区中一共有64个连续的页。为了保证区的连续性,InnoDB会一次性申请4-5个区。

2.4 页

页是InnoDB磁盘管理的最小单位,默认大小为16KB。InnoDB引入了压缩页,页的大小可以设置为2KB、4KB、8KB。

InnoDB的页类型有数据页(索引页)、Blob页、Undo页、系统页等等,常见的页类型有:

  • 数据页(B-Tree Node)
  • uodo 页(undo Log Page)
  • 未压缩的二进制大对象页(Uncompressed BLOB Page)
  • 压缩的二进制大对象页(Compressed BLOB Page)
  • 事务数据页(Transaction System Page)
  • 插入缓存位图页(Insert Buffer Bitmap)
  • 插入缓存空闲页列表(Insert Bufffer Free List)

2.4 行

InnoDB存储引擎是面向行的(row-oriented),即数据是按照行存放在Page中。

3. 数据页(索引页)结构

InnoDB采用数据页的形式组织数据,默认的非压缩数据页为16KB。在ibd中间中,0-16KB偏移量即为0号数据页,16KB-32KB的为1号数据页,依次类推。

数据页大致上可以分三部分,一部分存储页的基本信息;一部分存储数据记录,按照记录的键值大小顺序存储、通过记录的指针单向连接起来;另外一部分存储数据页的目录,用来加速查找。注意这个目录是稀疏的,即不是所有的记录在目录都有索引,平均是每隔六个记录才有一个目录。

在这里插入图片描述

File Header 数据页文件头
File Header用来记录一些页的头信息、表空间的相关信息,比如当前页的上、下页指针,所以在B+树中,叶子节点是双向链表。InnoDB数据页在逻辑上是连续的,但是在物理上,由于数据页的不断分配和释放,可能是离散的。

Page Header 数据页头
Page Header记录数据页的状态信息、元数据,比如页中的记录数

Infimum、Supremum Record 最小最大记录
虚拟记录,用来限定记录的边界,分别代表最小和最大记录。譬如,Infimum比页中所有真实的记录都小。

在这里插入图片描述

User Record 用户记录

User Record实际存储了行记录,按照键顺序排序,记录之间通过单向链表连接(指向下一条记录)。默认记录之间是紧挨着的,但如果重用了已删除记录的空间,则可能会产生空间碎片(原有空间大于新的记录长度)。

Free Space 空闲空间

记录空闲空间。

Page Dictory 页目录

Page Dictory是一个稀疏目录,按照键值顺序存储着记录的相对位置(相对于页),利用二分法可以迅速找到记录指针。目录里的记录指针称之为目录槽(Dictory Slots),由于InnoDB的目录是稀疏的,所有并不是每条记录都拥有一个槽,平均6个记录公用一个目录槽。譬如,有(a, b, c, d, e, f, g, h, i, j, k),那么页目录可能为(a, e, i)。

由于InnoDB的Page Dictory是稀疏目录,二分查找只是一个大致位置,而后必须通过记录的指针继续查找目标记录。

B+树索引本身并不能定位到具体的一条记录,只能先定位到该记录所在的页,数据库将页载入内存后,再通过页目录的稀疏目录进行大致定位,最后利用记录之间的单向链表指针找到目标记录。

File Trailer

记录页的checksum等信息,用以校验页的完成性。

4. 行记录格式

InnoDB存储引擎是面向行的(row-oriented),即数据是按照行存放在Page中。InnoDB支持4中行记录格式,常见的有:Compact、Dynamic和Compressed。

MySQL 5.7中的默认行记录格式为Dynamic。

4.1 Compact 行记录格式

Compact是一种高效的行记录格式,其目标是高效的存储数据,较REDUNDANT能够减少20%左右的空间占用,但代价是会增加某些操作的CPU占用率。

4.1.1 整体结构

变长字段长度列表

Compact行记录格式的首部是变长字段长度列表,存储着非NULL变长字段的实际长度。因为MySQL中VARCHAR类型的最大长度不能超过65535,所以每个字段长度最多用2个字节就可以表示。

NULL标志位

变长字段长度列表的后边是NULL标志位,表示了可以为NULL的列中,哪些列实际为NULL,若为NULL则该位标记为1。该部分的长度依赖于该表中可以为NULL列的个数,譬如,该表定义中有9列可以为NULL,那么需要2个字节的比特向量才能表示9个列的NULL情况。

实际为NULL的列(无论是VARCHAR还是CAHR)除了在NULL标志位中占用一个比特位外,不会再占用其它空间。

记录头信息

接下来是记录头信息,占用5个字节,记录着改行记录的基本信息。例如:

  • 是否被删除
  • 指针:下一条记录的相对位置,InnoDB页内通过链表将行记录串联起来。

实际数据

记录头信息的后面开始存储实际每列的数据,实际为NULL的列不占据空间。除了用户定义的列外,还有两个隐藏列:事务ID和回滚指针列。如果没用定义主键,那么还会有一个6字节大小的rowid列。

对于辅助索引,该部分存储的是该行记录的主键。若主键的部分列(MySQL支持复合索引)已经包含辅助索引中,则不会再重复记录。

4.1.2 不同类型的数据如何存储

CHAR

对于固定长度的CHAR类型,缺少的字符会以0x20填充。

由于CHAR(N)中的N指的是字符个数,对于变长字符集(比如UTF-8),其实际字节长度不是定长数据。此时,InnoDB将其视为变长字符类型,在变成字符长度列表中也会记录CHAR类型字段的实际长度。因此,在使用变长字符集的情况下,CHAR和VARCHAR在存储上没有区别。

VARCHAR

VARCHAR(N)中的N指的是字符个数,VARCCHAR的最大字节长度不能超过65532(较65535小,因为有其它开销)。例如,在UTF-8符集下,N的最大值要在最大字节长度上再除以3。

PS:
MySQL中的UTF-8字符集并不是标准的UTF-8,其最多支持3个字节,而标准的UTF-8使用1-4字节来进行字符编码,故MySQL又推出了UTF-8 mb4来进行弥补。

行溢出

一般情况下,行数据都是放在页中的,但是,对于一些长度较长的列数据,InnoDB会将存储在数据页外,存储在Uncompress BOLB页中。VARCHAR、BLOB、TEXT都可能发生行溢出,但长度较短时,即使是BOLB也可能完全存储在页内。

是否发生行溢出,取决于页的大小和行的大小,InnoDB会保证一个数据页至少存储两行记录。

当生行溢出时,在Compact行格式下,数据页中会存储前768个字节,然后再存储一个20字节的指针,指向行溢出页。

在这里插入图片描述

在Dynamic和Compressed行记录格式下,会采用完全行溢出的方式,在数据页只存在指针,不再存放列的前缀字节。

4.2 Dynamic和Compressed行记录格式

Dynamic和Compressed行记录格式在Compact的基础进行了改进,都采用完全行溢出的方式,在数据页只保存指针,不再存放列的前缀字节。

Compressed行记录格式的另一个功能是,会对存储的行数据进行压缩(zlib),因此对于BLOB、TEXT、VARCHAR等大长度类型的数据能够进行更加有效的存储。

参考文档

《MysSQL技术内幕(InnoDB存储引擎)》
淘宝数据库内核月报:MySQL · 专家投稿 · InnoDB物理行中null值的存储的推断与验证
MySQL官网:InnoDB Row Formats

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值