本文将介绍InnoDB存储引擎表的逻辑存储及实现,重点讲表的物理存储特性,即数据在表中是如何组织和存放的;
索引组织表
表都是根据主键顺序组织存放的,这种存储方式的表被称为索引组织表;
每张表都有个主键(Primary Key),如果在创建表的时候,没有显式地定义主键,则InnoDB存储引擎会依据以下规则选择或创建主键:
1.首先,判断表中是否有非空的唯一索引(Unique NOT NULL),如果有,则该列为主键;
2.如果不符合上述条件,InnoDB会自动创建一个6byte大小的指针;
当表中有多个非空唯一索引的时候,InnoDB会选择建表时第一个定义的非空唯一索引作为主键;
需要注意的是,这里的“第一个定义”指的不是建表时列的顺序,而是定义索引的顺序;
举个例子:
表z中有a,b,c,d四个列,b,c,d三列是唯一索引,不同的是b允许为NULL;由于没有显式地定义主键,因此会选择非空的唯一索引,所以只能c和d中选择;但在定义的时候,是d先被定义为唯一索引(UNIQUE KEY),所以选择d为主键;
InnoDB逻辑存储结构
从上图可看出,所有数据都被逻辑地放在一个空间中,称之为表空间(tablespace);
表空间又分为:段(segment),区(extent),页(page)组成;
表空间(tablespace)
是存储引擎逻辑结构中的最高层,所有的数据都存放在表空间中;
之前介绍的,默认情况下,InnoDB存储引擎中有一个共享表空间ibdata1,即所有数据都存放在这个表空间内;
如果用户启动了参数innodb_file_per_table,则每张表内的数据可以单独放到一个表空间内;当然,每张表的表空间存放的只是数据,索引和插入缓冲Bitmap页,其他的数据,如回滚信息,插入缓冲索引页,系统事务信息,二次写缓冲等还是存放在原来的共享表空间内;
所以,共享表空间还是会不断地增大;
段(Segment)
表空间是由好几个段组成的,常见的段有数据段,索引段,回滚段等;
前面已经讲了,表是索引表,即存储引擎是索引组织的,因此数据即索引,索引即数据;所以,数据段即为B+树的叶子节点,索引段为B+树的非索引节点;回滚段比较特殊;
区(Extent)
区是由连续的几个页组成的空间,每个区的大小为1MB;为了保证区中页的连续性,存储引擎会一次从磁盘申请4~5个区;在默认情况下,每个页的大小为16KB,即一个区共用64个连续的页;
压缩页,设置页大小;
页(Page)
页是InnoDB磁盘管理的最小单位;
常见的页有:1.数据页(B-tree Node);2.undo页;3.系统页;4.事务数据页;5.插入缓冲位图页;6.插入缓冲空闲列表页;7.未压缩的二进制大对象页;8.压缩的二进制大对象页;
行(Row)
数据是按行进行存放的;
InnoDB行记录格式
数据是按行进行存放的,即页中保存着表中一行行的数据;使用Compact(使用最多)和Redundant两种格式来存放行记录数据;
Compact行记录格式
一个页中存放的行数据越多,性能就越好;
NULL标志位:指示该行数据中是否有NULL值,有则用1表示,该字段占1个字节;
记录头信息:占5个字节(40位)
每行数据除了用户定义的列外,还有两个隐藏的列,事务ID列和回滚指针列,分别为6字节和7字节;若InnoDB表没有定义主键,每行还会增加一个6字节的rowid列;
InnoDB数据页结构
页是InnoDB存储引擎管理数据库的最小磁盘单位;页类型是B-tree Node的页存放的是表中行的实际数据;