表
表就是关于特定实体的数据集合,是关系型数据库的核心
索引组织表
在InnoDB存储引擎中,表中的数据都是根据主键顺序组织存放的,这种存储方式的表称为索引组织表
所以在InnoDB存储的引擎表中,都必须有个主键(primary key),如果在创建表时没有显示地定义主键,则InnoDB存储引擎会按照下面的方式选择或者创建主键
- 首先判断表中是否有非空的唯一索引,即unique key not null,如果有,那么该列就会变为主键(rowid)
- 如果有多个非空的唯一索引,则会选择建表时第一个定义的非空唯一索引作为主键(rowid)
- 如果不符合上述条件,InnoDB存储引擎将自动创建一个6字节大小的指针(rowid)
举个栗子
CREATE TABLE z(
a INT NOT NULL,
b INT NULL,
c INT NOT NULL,
d INT NOT NULL,
UNIQUE KEY(b),
UNIQUE KEY(c),
UNIQUE KEY(d)
)ENGINE=INNODB,CHARSET=utf8;
从建表上看,可以看到b、c、d列都有唯一索引,但b可以为NUll,故不可以充当主键,而第一个非空唯一索引是c列,所以c将会充当主键。
//插入几条数据
INSERT INTO z SELECT 1,2,3,4;
INSERT INTO z SELECT 1,3,4,5;
INSERT INTO z SELECT 1,4,5,6;
INSERT INTO z SELECT 1,5,6,7;
//查询情况,_rowid可以判断主键是哪一列
SELECT a,b,c,d,_rowid FROM z;
结果如下所示
可以看到**_rowid**跟c列一模一样,所以可以确定c列成为了主键
但是**_rowid**只可以看单个列作为主键的情况,如果使用多个列作为主键是查询不了的
//当遇到下面的建表语句是无法使用rowid查询的
CREATE TABLE z2(
a INT NOT NULL,
b INT NOT NULL,
c INT NOT NULL,
PRIMARY KEY(a,b)
)ENGINE=INNODB,CHARSET=utf8;
InnoDB逻辑存储结构
从InnoDB存储的逻辑存储结构看,所有数据都被逻辑地存放在一个空间里面,称之为表空间(tablespace)。而表空间又由段(segment)、区(extent)、页(page)组成,页有时也会被成为块。
其实是段里面的是区,区里面的是页,页里面还有行
表空间
前面的InnoDB存储文件提到过,所有的数据都是存放在表空间里面的,默认会有一个表空间ibdata1,即所有的数据都会在该表空间里面,不过前面也提到过,如果开启了参数innodb_file_per_table,则每张表内的数据可以单独放到一个表空间内,不过单独的表空间里面只存放的数数据、索引和插入缓冲Bitmap页,其他信息,比如插入缓冲的索引页,回滚信息,锁信息,二次写缓冲等还是存放在原来的共享表空间里面。
这同时也说明了一个问题,即使开启了参数innodb_file_per_table,共享表空间也是会不断增加其大小的,会继续膨胀。
段
表空间是由各个段组成的,常见的段有数据段、索引段、回滚段等。
数据段其实就是InnoDB索引底层实现结构的B+树的叶子结点(leaf node segment),索引段即为B+树的非索引结点(Non-leaf node segement),回滚段则比较特殊,后面在介绍
在InnoDB存储引擎中,对段的管理都是由引擎自身所完成的,用户没有权限去进行管理,同时也没有必要去管理。
区
区是由连续页组成的空间,任何情况下,区的大小都为1MB( 2 10 K B 2^{10}KB 210KB),为了保证区中页的连续性(因为页是存储真正数据的,为了让页的存放可以连续,不要断开到另一个区),所以InnoDB存储引擎一次从磁盘申请4~5个区,在默认情况下,InnoDB存储引擎页的大小为16KB( 2 6 K B 2^6KB 26KB),即一个区中一共有64( 2 8 K B 2^8KB 28KB)个连续的页。
InnoDB中可以使用InnoDB_page_size参数去控制每页的大小,可以设置为4K、8K(默认为16K),这样的话,区中存放的页的数量就会相应的变为256和128,但区的大小仍然为1MB,这是雷打不动的
SHOW VARIABLES LIKE "innodb_page_size";
默认如下
但是,当用户启用了innodb_file_per_table后,创建的表默认大小是96KB,而一个区至少是1MB,所以创建的表应该至少也为1MB才对,为什么会这样?
其实这是因为,在每隔段开始时,会先用32个页大小的碎片页来存放数据,在使用完这些碎片页才会进行区的申请(直接申请4~5个区),这样做的目的在于,对于一些小表,可以在开始时就占用比较少的空间,节省磁盘容量的开销。
页
页是InnoDB磁盘管理的最小单位,默认的页大小为16KB,可以通过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)的,也就是说数据是按行来进行存放的(数据表中的一行),而每个页的存放的行记录也是有硬性定义的,最多允许存放7992数量的行记录(计算公式为16 * 1024 /2 - 200,16是指页的大小为16KB)。