1. InnoDB逻辑存储结构
所有的数据都被放在一个空间中,这个空间称为表空间(table space),表空间又由段(segmet)、区(extent)和页(page)组成,如下图所示。
(1)表空间(table space)
表空间是存储引擎的最高层,所有的数据都存放在表空间中。表空间可以看做一个逻辑概念,InnoDB 把数据保存在表空间,本质上是一个或多个磁盘文件组成的虚拟文件系统。如果没有开启innodb_file_per_table,则所有数据都存放在默认的共享表空间中,如果开启这个参数,那么,每张表的数据可以单独放到一个表空间中。表空间就是存放表的地方,它可以是一个物理文件,也可以是多个物理文件的集合,可以通过参数innodb_data_file_path进行设置。
(2)段(segment)
由于InnoDB存粗引擎是索引组织的,因此数据即索引,索引即数据。B+树的叶子节点即为数据段,B+树的非叶子节点即为索引段,除了数据段和索引段之外,表空间还包含回滚段。
(3)区(extent)
一个段通常由多个区组成,每个区大小固定为1MB,为了保证页的连续性,InnoDB存储引擎一次从磁盘申请4~5个区。表空间增长时,表空间会按连续64个页的大小开始增长。
(4)页(page)
区由页组成,默认情况下,InnoDB存储引擎的页大小为16KB,因此一个区由64个连续的页组成,页是InnoDB磁盘管理的最小单位。
InnoDB1.0.x版本引入了压缩页,即每个页的大小可以通过参数KEY_BLOCK_SIZE设置为2K、4K、8K,因此每个区对应页的数量就应该为512、256、128.
InnoDB1.2.x版本新增了参数innodb_page_size,通过该参数可以将默认页的大小设置为4K,8K,但是页中的数据是不压缩的,这时区的数量同样也为256,128,总之,不论页的大小怎么变化,区的大小总是为1MB。
在InnoDB存储引擎中,常见的页类型有:
- 数据页
- undo页
- 系统页
- 事务数据页
- 插入缓冲位图页
- 插入缓冲空闲列表页
- 未压缩的二进制大对象页
- 压缩的二进制大对象页
(5)行(row)
InnoDB的数据是按行进行存储的,每个页存放的行记录也是有硬性规定的,最多允许存放16K/2 - 200 = 7992行记录。
2. InnoDB行记录格式
InnoDB存储引擎提供了Compact和Redundant两种格式来存放行记录数据,Redundant格式是为兼容之前的版本而保留的,在MySQL5.1 版本中,默认设置为Compact行格式。
2.1 Compact行记录格式
Compact行记录是在MySQL5.0引入的,其设计的目的是高效的存储数据,它的存储方式如下图所示:
- 行记录首部是一个非NULL变长字段长度列表,并且是按照列的顺序逆序放置的,其长度为:1)若列的长度小于255字节,用1字节表示;2)若大于255字节,用2字节表示。变长字段的长度最大不超过2字节,这时因为MySQL数据库中VARCHAR类型的最大长度限制为65535。
- NULL标志位指示了该行数据中是否有NULL值,有则用1表示,该部分所占的字节应该为1字节。
- 记录头信息固定用5字节(40位),每位的含义如下:
名称 | 大小(bit) | 描述 |
() | 1 | 未知 |
() | 1 | 未知 |
deleted_flag | 1 | 该行是否已经被删除 |
min_rec_flag | 1 | 为1,如果该记录是预先被定义为最小的记录 |
n_owned | 4 | 该记录拥有的记录数 |
heap_no | 13 | 索引堆中该条记录的排序记录 |
record_type | 3 | 记录类型,000表示普通,001表示B+树节点指针,010表示Infimun,011表示Supremun,1xx表示保留 |
next_record | 16 | 页中下一条记录的相对位置 |
Total | 40 |
- 对于实际每列的数据,需要特别注意的是,NULL不占该部分任何空间,即NULL除了占有NULL标志位,实际存储不占有任何空间。
- 每行数据除了用户定义的列外,还有两个隐藏列,分别是事务ID列和回滚指针列,分别为6字节和7字节大小,如果InnoDB没有定义主键,每行还会增加一个6字节的rowid列。
- 不管是CHAR型还是VARCHAR型,在compact格式下NULL值都不占任何存储空间。固定长度CHAR字段在未能完全占用其长度空间时,会用0x20来进行填充。
2.2 Redundant行记录格式
Redundant是MySQL 5.0版本之前的行记录存储方式,它的行记录存储格式如下:
- 字段长度偏移列表同样是按照列的顺序逆序放置的,若列的长度小于255字节,用1字节表示,若大于255字节,用2字节表示。
- 记录头信息占用6字节(48bit),每位的含义如下表所示:
名称 | 大小(bit) | 描述 |
() | 1 | 未知 |