1、背景
本文主要介绍MySQL中ibd文件的存储结构,并配套开发了解析ibd文件的代码:https://github.com/jemuelmiao/parseibd,该代码输出结果可以一目了然的看到ibd文件中当前的存储结构、btree中page的连接关系、聚簇索引或二级索引的组织格式等。
2、表空间
MySQL中最顶层的逻辑管理结构是表空间,根据用途表空间分为如下几类:
- 系统表空间:存放数据字典(data dict)、双写缓存(double write buffer)、变更缓存(change buffer)、回滚日志(undo log)及可能的表数据和索引。文件信息由innodb_data_home_dir和innodb_data_file_path控制,默认情况下有一个ibdata1文件。
- 独占表空间:存放表数据和索引,是否开启由innodb_file_per_table控制,默认开启,开启后每个表会生成独立的ibd文件。
- 通用表空间:通过create tablespace语法创建的共享表空间。
- Undo表空间:存放undo log,文件路径由innodb_undo_directory控制,表空间个数由innodb_undo_tablespaces控制,undo log默认存储在系统表空间中。
- 临时表空间:存放临时表,文件路径由innodb_temp_data_file_path控制。
3、ibd文件
由上节可以知道ibd文件是innodb用于管理表数据和索引的文件,默认情况下每个表会生成一个独立的ibd文件。
Ibd文件中最小存储单元是page,默认情况下每个page是16K,大小由innodb_page_size控制。Ibd中的page包含多种不同类型,每种类型有特定的存储格式及作用,本文接下来会详细介绍几种类型。
Ibd文件总体结构如下图所示:
整个ibd文件中所有page属于同一个表空间,ibd文件前3个page是固定的,分别是page fsp、page ibuf、page inode,它们的作用后文会详细介绍到。从逻辑层次上,ibd文件可以划分为:space(表空间)、segment(段)、extent(区)、page(页),其中前者用于管理后者。
3.1 page类型
3.2 page头部
在ibd中每个page具有相同的头部,该头部占用固定38字节大小,各字段信息如下(参考源码fil0fil.h):
3.3 page尾部
同样在ibd中每个page具有相同的尾部,该尾部占用固定8字节大小,字段信息如下(参考源码fil0fil.h):
4、FIL_PAGE_TYPE_FSP_HDR
FSP page是ibd文件的第一个page,主要用于管理全局extent列表、全局inode page列表。FSP page的总体结构如下图所示:
4.1 FSP page格式
4.1.1 FSP Header格式
FSP Header字段信息如下:
flst_base_node_t是通用的链表头节点结构,字段信息如下:
fil_addr_t是通用的节点地址结构,字段信息如下:
4.1.2 Extent Descriptor格式
Extent Descriptor字段信息如下:
flst_node_t是通用的双向链表指针结构,字段信息如下:
extent状态标志如下:
XDES_BITMAP是extent用于管理紧随当前所在页之后的page,每个page占用2bit,一个extent可以管理64个page,结构如下:
4.2 Extent链表管理
Ibd文件中的全局extent链表在FSP page中进行管理,包括空闲extent链表、碎片extent链表、满extent链表,分别由FSP Header中字段FSP_FREE、FSP_FREE_FRAG、FSP_FULL_FRAG表示,每个extent链表中的元素是Extent Descriptor结构,一个FSP page最多包含256个Extent Descriptor,一个Extent Descriptor最多管理64个page,也就是说一个FSP page最多管理16384个page,当page不够时,需要扩展Extent Descriptor,这是通过增加类型为FIL_PAGE_TYPE_XDES的page来完成的,该类型的page和FSP page除了FSP Header不同外,其他一样,主要是为了扩展Extent Descriptor,详细见后文。
全局extent链表管理关系如下图所示:
链表中的Extent Descriptor元素可能来自FSP page或XDES page。
Extent Descriptor用于管理page,每个Extent Descriptor最多管理随后的64个page,例如:Extent Descriptor 0管理page 0至page 63,Extent Descriptor 1管理page 64至page 127,依次类推。管理关系如下所示:
4.3 Inode page链表管理
Ibd文件中的全局inode page链表在FSP page中进行管理,包括满inode page链表、可用inode page链表,分别由FSP Header中字段FSP_SEG_INODES_FULL、FSP_SEG_INODES_FREE表示,每个inode page链表中的元素是page。全局inode page 链表管理关系如下图所示:
5、FIL_PAGE_TYPE_XDES
XDES page主要用于扩展extent Descriptor,该page结构和FSP page类似,唯一不同点在于不使用FSP Header部分,如下所示:
6、FIL_PAGE_IBUF_BITMAP
IBUF page是ibd文件的第二个page,主要用于管理随后page的change buffer信息。IBUF page总体结构如下图所示:
6.1 IBUF page格式
6.2 Ibuf Bitmap
Ibuf Bitmap用于管理随后page的change buffer信息,每4bit表示一个page,字段信息如下:
7、FIL_PAGE_INODE
Inode page是ibd文件的第三个page,主要用于管理segment。Inode page总体结构如下图所示:
7.1 Inode page格式
Inode page主体字段信息如下:
Segment Inode字段信息如下:
7.2 Segment管理
每个segment inode代表一个segment,segment用于管理使用的extent,包括空闲extent链表、部分使用extent链表、满extent链表,分别由字段FSEG_FREE、FSEG_NOT_FULL、FSEG_FULL表示,管理关系如下所示:
8、FIL_PAGE_INDEX
Index page用于存储数据和索引。Index page总体结构如下图所示:
8.1 Index page格式
Index page主体字段信息如下:
Page Header字段信息如下:
fseg_header_t字段信息如下:
8.2 记录存储格式
Innodb行格式有四种:redundant、compact、compressed、dynamic,参考源码:rem0types.h/rec_format_enum。其中redundant为旧格式,compact、compressed、dynamic为新格式,新旧格式在记录存储格式上差异较大。接来下会详细介绍不同格式下记录的存储方式。
8.2.1 新行格式
新行格式包括:compact、compressed、dynamic。
8.2.1.1 记录头信息
每个记录前都有固定的记录头REC_N_NEW_EXTRA_BYTES,用于存储记录相关的属性,格式如下:
8.2.1.2 系统记录
每个index page中会自动生成两个系统记录:infimum、supremum,分别是最小记录、最大记录。
Infimum记录存储格式:
Supremum记录存储格式:
8.2.1.3 用户记录
用户记录存储格式如下:
实际数据根据索引类型存储方式不一样,分为:聚簇索引非叶子节点、聚簇索引叶子节点、二级索引非叶子节点、二级索引叶子节点。格式如下:
聚簇索引非叶子节点:
聚簇索引叶子节点:
二级索引非叶子节点:
二级索引叶子节点:
8.2.2 旧行格式
旧行格式包括:redundant。
8.2.2.1 记录头信息
每个记录前都有固定的记录头REC_N_OLD_EXTRA_BYTES,用于存储记录相关的属性,格式如下:
8.2.2.2 系统记录
Infimum记录存储格式:
Supremum记录存储格式:
8.2.2.3 用户记录
用户记录存储格式如下:
实际数据根据索引类型存储方式不一样,分为:聚簇索引非叶子节点、聚簇索引叶子节点、二级索引非叶子节点、二级索引叶子节点。格式如下:
聚簇索引非叶子节点:
聚簇索引叶子节点:
二级索引非叶子节点:
二级索引叶子节点:
9、FIL_PAGE_TYPE_BLOB
Blob page用于长度较大的变长字段。Blob page总体结构如下图所示:
9.1 Blob page格式
Blob page主体字段信息如下:
Blob Header字段信息如下:
10、数据类型
MySQL数据类型分为两种:MySQL层数据类型、引擎层数据类型,引擎层数据类型以innodb数据类型介绍。
10.1 innodb数据类型
Innodb数据类型分为主数据类型(main type)、精确数据类型(precise data type)。主数据类型主要用于定义基本类型,精确数据类型主要用于定义类型的相关属性,参考源码:data0type.h。
精确数据类型包括:
关于是否可变长度类型,可以参考源码:data0type.ic/dtype_get_fixed_size_low(),返回值为非0时表示固定长度类型,0表示可变长度类型。
10.2 mysql数据类型
参考源码:binary_log_types.h/enum_field_types,MySQL层数据类型主要包括:
关于mysql数据类型转换为innodb数据类型,参考源码:ha_innodb.cc/get_innobase_type_from_mysql_type()。
10.3 常用数据类型存储
10.3.1 decimal
decimal分为整数部分、小数部分,整数部分和小数部分的每9位数字使用4个字节存储为一个整数,不足9位数字的使用如下规则存储为一个整数:
当decimal数据为正数时,最高位设为1,为负数时,最高位设为0,并且其余位取反。decimal数据存储可参考源码:decimal.c/decimal2bin()、decimal.c/bin2decimal()。
10.3.2 int
int数据为signed时,需要翻转符号位。
10.3.3 year
year数据存储时需要减1900。
10.3.4 日期类型
11、文件解析
为了方便查看ibd文件结构,开发了解析ibd文件的代码:https://github.com/jemuelmiao/parseibd。
文章评论