一、索引组织表

在InnoDB存储引擎中,表都是根据主键组织存放的,这种存储方式的表称为索引组织表。

在InnoDB存储引擎中,每个表都有主键,如果在创建表的时候没有显示创建主键,则InnoDB存储引擎会按如下方式选择或创建主键

  • 首先判断表中是否有非空的唯一索引,如果有,则该列即为主键。
  • 如果不符合上述条件,InnoDB存储引擎自动创建一个6字节大小的指针。

当表中有多个非空唯一索引时,InnoDB存储引擎将选择建表时第一个定义的非空唯一索引为主键。

下面创建了一个表,这个表有4列,其中b,c,d列建立了唯一索引,但是b列允许为NULL。

MySQL技术内幕-InnoDB存储引擎-第四章、表
下面通过SQL判断哪个是主键,_rowid可以显示表的主键,所以d是主键,因为d是第一个创建的
MySQL技术内幕-InnoDB存储引擎-第四章、表
_rowid只能查看单个列为主键的情况,对于多个列为主键就不行了。
MySQL技术内幕-InnoDB存储引擎-第四章、表

二、InnoDB逻辑存储结构

从InnoDB存储引擎的逻辑存储结构看,所有数据被逻辑放在一个空间,成为表空间。
表空间又由段(Segment)、区(extent)、页(page)组成。页在一些文档中有时称为块。

MySQL技术内幕-InnoDB存储引擎-第四章、表

1、表空间(共享表空间ibdata1,如果一张表放在一个单独表空间,则放数据、索引和插入缓冲页)

表空间是InnoDB存储引擎结构的最高层,所有的数据都存在表空间。默认情况下,InnoDB有一个共享表空间ibdata1,所有的数据都存在这个表空间中,如果启用了参数innodb_file_per_table,则每张表的数据会单独放在一个表空间中。

如果启用了innodb_file_per_table的参数,需要注意的是每张表的表空间存放的只是数据、索引和插入缓冲Bitmap页,其他类数据,如回滚信息、插入缓冲索引页、系统事务信息,两次血缓冲等还是放在原来的共享表空间内。所以即使一张表存放在一个表空间,但是共享表空间的大小还是不断增大的。

2、段(数据段为叶子节点,索引段为非叶子节点)

表是由段组成的,常见的段有数据段、索引段、回滚段等,InnoDB存储引擎表是索引组织的。那么数据段是B+树的叶子节点,索引段为B+树的非叶子节点。回滚段在后面讲解。

3、区(由连续页组成,1个区1MB)

区由页组成,每个区大小为1MB。区中也是连续的,InnoDB一次从磁盘申请4-5个区,在默认情况下,InnoDB存储引擎页的大小为16kb,即64个连续页。
InnoDB1.2.x版本新加了参数innodb_page_size,通过该参数可以将默认的页的大小设置为2k、4k、8k,因此每个区对应页的数量应该为512,256、128.

虽然区的大小为1MB,但是不能说明表的大小最小为1MB,因为可以使用碎片页来存放数据。

4、页(InnoDB磁盘管理的最小单位)

InnoDB存储引擎中,页的大小默认为16kb,从InnoDB1.2.x版本开始,可以通过参数innodb_page_size进行设置。
MySQL技术内幕-InnoDB存储引擎-第四章、表

三、InnoDB行记录格式

InnoDB提供了Compact和Redundant两种格式来存在行记录数据。
Redundant格式为兼容之前的版本而保留的,在MySQL5.1版本中,默认为Compact行格式,用户可以通过show table status like 'table_name’来查看当前表使用的行格式,row_format属性表示当前使用的行记录结构类型。

1、Compact行记录格式

英 [kəmˈpækt , ˈkɒmpækt]adj. 小型的; 袖珍的; 紧凑的; 体积小的;

一个页中存放的行数据越多,性能越高。
Compact行记录是在MySQL5.0中引入的,其设计目标是高效存储数据。
MySQL技术内幕-InnoDB存储引擎-第四章、表
Compact行记录格式的首部是一个非null变长字段长度列表,并且其是按照列的顺序存放的

  • 如果列的长度小于255字节,用一个字节表示
  • 如果大于255字节,用2字节表示

变长字段的长度不超过2字节,这就是为什么varchar类型的最大长度限制为65535。这个空间可能有多个,可能是根据有多少个varchar字段来定的

变长字段后面的第二个部分是NULL标识位,表示了该行数据中是否有NULL值,有则用1表示。
再下面是头部信息,固定是5字节(40位),每位的含义如下:
MySQL技术内幕-InnoDB存储引擎-第四章、表

注意(NULL除了有NULL标识位,实际不存储任何空间,每行有两个隐藏列,存事务ID和回滚指针列)

  • NULL除了有NULL标识位,实际不存储任何空间
  • 每行数据有两个隐藏列,存放事务ID和回滚指针列,分别占用6字节和7字节的大小
  • 如果InnoDB没有定义主键,每行还会增加一个6字节的rowid列。

例子

MySQL技术内幕-InnoDB存储引擎-第四章、表
MySQL技术内幕-InnoDB存储引擎-第四章、表
t1、t2、t4是varchar类型的即变长的,t3为固定长度类型char
插入一个数据,打开空间文件mytest.ibd。
MySQL技术内幕-InnoDB存储引擎-第四章、表
MySQL技术内幕-InnoDB存储引擎-第四章、表

2、Redundant行记录格式

3、行溢出数据

4、Compressed和Dynamic行记录格式

5、CHAR的行结构存储(char定义时候的长度是字符长度,不是字节长度,不同字符所占字节可能会不同)

通常理解varchar是变长长度的字符类型,char是固定长度的字符类型。

从MySQL4.1版本开始,CHAR(N)中的N指的是字符的长度,而不是之前版本的字节长度。
也就是说在不同的字符集下,char类型列内部存储的可能不是定长的数据,要看字符怎么编码,每个字符的编码长度可能是不同的。

MySQL技术内幕-InnoDB存储引擎-第四章、表

MySQL技术内幕-InnoDB存储引擎-第四章、表

MySQL技术内幕-InnoDB存储引擎-第四章、表
在上面的例子中,表j的字符集是GBK,插入了‘ab’和‘我们’,查看所占字节:
MySQL技术内幕-InnoDB存储引擎-第四章、表
‘ab’占2字节,‘我们’占4字节。
对于UTF-8下char(10)类型的列,其最小可以存储10字节的字符,最大可以存储30字节的字符。

对于多字节字符编码的char数据类型的存储,InnoDB存储引擎在内部将其视为变长字符类型。

四、InnoDB数据页结构

MySQL技术内幕-InnoDB存储引擎-第四章、表
为了验证页是否完整写入磁盘,在File Trailer只有一个FIL_PAGE_END_LSN部分,占8字节,其中前面4字节是校验和,最后四字节和File Header中的FIL_PAGE_LSN相同,将这两个值和FIle Header中的FIL_PAGE_SPACE_OR_CHKSUM和FIL_PAGE_LSN值进行比较,看是否一致,以此保证页的完整。
其他略。

六、约束

1、数据完整性

相关文章: