Innodb存储

Innodb存储

Posted by CaiJiahe on August 10, 2017

0x01 逻辑存储结构

表空间:存储数据、索引、插入缓冲bitmap页、回滚数据、插入缓冲索引页、事务信息、二次写缓冲(开启innodb_file_per_table后,除存储数据、索引、插入缓冲bitmap页外,都存在在共享表空间中)。每个表空间可以存在多个文件,第一个文件被称为0号文件,存储满簇、半满簇和空闲簇链表头和一些例如表空间id的元数据。
:表空间的组成单位,分为数据段、索引段、回滚段等。勿需管理,段管理的空间是无限大的,每个段也有满簇、半满簇和空闲簇链表来管理本段内的簇。
区(簇):大小固定为1M(页的大小*页的数量=1M)。开启innodb_file_per_table后,默认分配96KB空间(32个碎片页,为了小表节省磁盘)存数据。默认一个区存放64个页。
:innodb磁盘管理最小单位,大小通过innodb_page_size来设置。类型分为数据页、undo页、系统页、事务数据页、插入缓冲位图页、插入缓冲空闲列表页、未压缩的二进制大对象页、压缩的二进制大对象页。默认大小16K
:innodb存储引擎面向列,行存储。每个页存放16K/(2~200)个行,最多存放7992行数据。

0x02 行记录格式

隐藏列

innodb有隐藏列TransactionId和Roll Pointer

innodb 1.0.x之前

1.0.x之前的版本提供了Compact和Redundant两种格式来存储数据。

——————————————————————————
Compact:| 变长字段长度列表 | NULL标志位 | 记录头信息 | 列1 | 列2 | … |
——————————————————————————
变长字段长度会逆序指出哪列是有数据的变长字段。
NULL标志位会按位存储哪列为NULL,这样NULL就不占存储空间了。
头信息固定5字节。

——————————————————————-
Redundant:| 字段长度偏移列表 | 记录头信息 | 列1 | 列2 | … |
——————————————————————-
字段长度偏移列表逆序指出每列的长度。
Redundant对varchar的NULL值不占空间,但是对char的NULL值需要占空间存储。

innodb 1.0.x之后

1.0.x之后的版本引入了新的文件格式Barracuda,相比于原来的文件格式Antelope,又提供了Compressed和Dynamic两种格式来存储数据。
从mysql4.1开始,char(N)中的N不再指字节,而是字符数。在对多字节字符集类型存储的时候,从定长字符类型变为变长字符类型。
Compressed的另一个功能就是会以zlib算法进行压缩,对大数据的存储非常有效果。

行溢出数据

时机:如果一页内无法存入两行数据,就会发生行溢出。
Mysql中所有列使用的varchar总长度为65535字节(实际使用中可能还要打点折扣,而且不同编码的字符还会对存入的字符数产生影响)。
旧的两种格式一般数据会存放在B-tree Node中,当发生行溢出的时候,前768字节会存在B-tree Node中,其他的数据会存放在Uncompress BLOB页中。如果不发生行溢出,其实BLOB和TEXT类型也是直接存在数据页上的。
新的两种格式采用了完全的行溢出算法,数据页只存前20字节,其余数据放到Off Page中。

0x03 页格式

File Header:38字节,8个部分。checksum、页的偏移量、prev页、next页、log sequence num、页类型、更新到LSN值、页属于的表空间。
Page Header:数据页的状态信息,56个字节、14个部分。
Infimun + Supremun Records:每个数据页有两个虚拟的行,最小键值行和最大键值行,不会被删除,不同行格式占用字节不同。
User Records:行存储的空间。
Free Space;空闲空间,数据被删除后,挂到这个链表上。
Page Directory;存放行记录的页相对位置。B+树索引只能找到页,把页加载进内存后,根据Page Directory这个稀疏索引进行二分查找。
File Trailer;前4字节是checksum,后4字节存储lsn。每读取一个页都会根据trailer进行checksum,可以通过innodb_checksum_algorithm来选择算法,也可以通过参数innodb_checksums来控制是否检测。