表空间(tablespace)
- InnoDB的所有数据都放在表空间里,磁盘上对应的是ibd文件。
- 一个表空间由许多段(segment)组成
- 默认所有表的数据都放在共享表空间里
- 每个表的数据也可以放在独占表空间,配置innodb_file_per_talbe
段(segment)
- 一个段由许多区(extent)组成
- 常见的段有:
- Leaf node segment: 叶子结点段,也叫数据段,存储的是索引,指针和对应的数据(聚簇索引存储的是索引+完整数据,辅助索引存储的是索引+主键)
- Non-Leaf node segment:非叶子结点段,也叫索引段,只存储索引和指针
- Rollback segment: 回滚段,记录用于回滚的相关信息
- 段是由InnoDB自动管理
区(extent)
- 区是由连续页组成的空间,大小为1MB
- 一次从磁盘申请4~5个区
- 一个区一般有64页(page)
- 在配置innodb_file_per_talbe后,创建表会初始申请32页的碎片页(fragment page),也就是96KB来存放数据,用完之后才是以64页为一个区一个区的申请
页(page)
- 页是InnoDB中磁盘读写的最小逻辑单位,默认为16KB
- 页的大小是充分考虑了机械硬盘和SSD的最小读写单位(512B和4KB)
- 常见的页类型有:
- 数据页(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)
- 一个数据页就是一个B+树节点(B+ Tree Node)
- 数据页一般由7个部分组成
- File Header用来记录页的一些头信息
- Page Header用来记录数据页的状态信息
- 每个页中都有两个虚拟行记录,用来限定记录的边界:Infimum和Supremum Record
- User Record是实际存储行记录的内容。
- Page Directory存放了记录的相对位置,这些记录指针也称为Slots(槽)。在Slots中记录按照索引键值顺序存放,这样可以利用二叉查找迅速找到记录的指针。
- File Trailer用于检测页是否完整地写入磁盘
行
在理解行数据结构时,我们首先要知道两个概念:变长列和行溢出数据
变长列
变长列值得是一个字段对应的不同行数据在存储中占用的大小时不固定的
- 长度不固定的数据类型: VARCHAR VARBINARY BLOB TEXT
- CHAR其实也是变长列,虽然CHAR的长度可以固定,但由于不同编码下相同字符串长度不相同,所以CHAR也是变长列
行溢出机制
当行数据中某个字段长度过长,会影响到一页数据所存储的行数据条数,从而影响到B+树的性能。所以InnoDB会将一条行数据中过长字段的数据单独存放到BLOB的页中,而在B+树叶子节点中存储指针。
-
这样的机制的优点是保证了单页行数据条数更多,降低磁盘IO,提升查询效率
-
缺点是在需要查询该长字段的数据时,需要去额外磁盘IO一次查询数据
行记录格式
InnoDB的行记录格式主要有四种
Redundant
MySQL5.0之前的默认格式
- 字段偏移列表:
- 记录每个字段的相应位置
- 按照列的顺序逆序放置
- Header: 列数量、字段偏移表的单位、下一行记录的指针信息等
- RowID: 没有可用主键时,使用RowID作为隐藏主键
- TxID: Transaction ID 事务ID
- Roll Pointer: 回滚指针
若遇到数据溢出
Compact
MySQL5.1默认格式
- 变长字段长度表:
- 每个变成字段的长度
- 按照列的顺序逆序放置
- NULL标志位:
- 指示行记录中的NULL值
- 每一个bit代表一个字段
若遇到数据溢出
Dynamic
MySQL5.7后默认格式
Dynamic相较与Compact就只改进了溢出机制
当数据长度小于40Byte时,存原数据,大于40Byte后就只存指针了
Compressed
- 物理结构和Dynamic相似
- 对表的数据行使用了zlib算法进行压缩
- 可以节约40%左右的空间,但对CPU压力大