MySQL表frm文件解析
说明:
以下所有说明都以 MySQL 5.7.25 源码为例 ,存储引擎为InnoDB。
MySQL .frm文件格式
MySQL会为每一个table在磁盘上创建一个.frm格式尾缀的文件,作为表定义文件,该文件与表名一致。
首先,创建一个表:
mysql> create table t1 (
a int not null comment 'comment on column a',
b int default 5 comment 'comment on column b',
primary key(a),
key idx_a(a),
key idx_b(b),
key idx_a_b(a,b),
key idx_b_comment(b) comment 'comment on key b'
) engine = innodb;
每个表的.frm文件会在mysql安装的data目录下,可以查看变量datadir查看具体路径。
mysql> select @@datadir;
+--------------------------------------------------+
| @@datadir |
+--------------------------------------------------+
| /opt/mysql/mysql-5.7.25/mysql/data/ |
+--------------------------------------------------+
确定table的具体database
mysql> select database();
+--------------------+
| database() |
+--------------------+
| innodb |
+--------------------+
每个database的table的.frm文件会创建在datadir/database_name/路径下,进入/opt/mysql/mysql-5.7.25/mysql/data/ innodb可以查看到:
shell> su root
shell> cd /opt/mysql/mysql-5.7.25/mysql/data/ innodb
shell> ls t1.*
table1.frm table1.MYD table1.MYI
shell> ls -l t1.*
-rw-rw---- 1 root root 8578 May 28 20:31 t1.frm
-rw-rw---- 1 root root 98304 May 28 20:31 t1.ibd
使用vi打开并且切换到命令模式,输入!xxd -g 1即可查看单字节的十六进制编码结果,也可以用hexdump查看。

表1 .frm 文件头部 Header 段区域
Tips:
下列表格属性说明:
- 偏移:
.frm文件头偏移量- 长度:字节个数
- 值:属性值
- 描述:简明描述
| 偏移 | 长度 | 值 | 描述 |
|---|---|---|---|
| 0000 | 1 | FE | 固定值 |
| 0001 | 1 | 01 | 固定值 |
| 0002 | 1 | 09 | FRM_VER+3+ MY_TEST(create_info->varchar) FRM_VER(6) (#define FRM_VER @DOT_FRM_VERSION@) ) DOT_FRM_VERSION(cmake/mysql_version.cmake) SET(DOT_FRM_VERSION “6”) |
| 0003 | 1 | 0c | InnoDB引擎(DB_TYPE数据库引擎类型,enum legacy_db_type) |
| 0004 | 1 | 03 | 固定值 (代码中0x01) |
| 0005 | 1 | 00 | 固定值 |
| 0006 | 2 | 0010 | IO_SIZE(拼成:0x1000=4096) |
| 0008 | 2 | 0100 | |
| 000a | 4 | 00300000 | (IO_SIZE+key_length+reclength+ create_info->extra_size) |
| 000e | 2 | df06 | tmp_key_length=key_length(key_length的计算公式在表格下方 ) |
| 0010 | 2 | 0900 | reclength |
| 0012 | 4 | 00000000 | create_info->max_rows |
| 0016 | 4 | 00000000 | create_info->min_rows |
| 001B | 1 | 02 | 固定值(Use long pack-fields) |
| 001C | 2 | a200 | key_info_length |
| 001e | 2 | 0800 | create_info->table_options also known as db_create_options? one possible option is HA_LONG_BLOB_PTR |
| 0020 | 1 | 00 | 固定值 |
| 0021 | 1 | 05 | 固定值(Mark for 5.0 frm file) |
| 0022 | 4 | 00000000 | create_info->avg_row_length |
| 0026 | 1 | 2e | create_info->default_table_charset (utf8mb4) |
| 0027 | 1 | 00 | 固定值 |
| 0028 | 1 | 00 | create_info->row_type |
| 0029 | 6 | 00…00 | 固定值(RAID support) |
| 002f | 4 | df060000 | key_length |
| 0033 | 4 | 25c600 | MYSQL_VERSION_ID(50725[C625])mysql_version.h |
| 0037 | 4 | 1f000000 | create_info->extra_size |
| 003b | 2 | 0000 | Reserved for extra_rec_buf_length |
| 003d | 1 | 00 | Reserved for default_part_db_type, but 09 if MyISAM with partitioning |
| 003e | 2 | 0000 | create_info->key_block_size |
| 0040 |
key_length = keys * (8 + MAX_REF_PARTS * 9 + NAME_LEN + 1) + 16 + key_comment_total_bytes
每一个索引:
8位作为key header
9位留给每一个索引的每一个列field
NAME_LEN为索引索引名称
最后的16代表:6位作为header,1位作为分隔符’\0’,9位预留?对齐?
keys: 表索引个数
MAX_REF_PARTS: 单个索引支持最多列数(16个)
NAME_LEN: =(NAME_CHAR_LEN*SYSTEM_CHARSET_MBMAXLEN)
NAME_CHAR_LEN: 64位,表名、列名长度
SYSTEM_CHARSET_MBMAXLEN: 3,系统字符集最大长度
key_comment_total_bytes: 16,无comment
所以key_length = 5*(8+16*9+64*3+1)+16+16 + 2 = 706 = 0x6df。
表2 .frm 索引 Key 信息段区域
根据头部 Header 信息中的 0004 中的 IO_SIZE 作偏移一个 IO_SIZE,即为索引 keys 信息区域。
此处 IO_SIZE 大小为 4096;
| 偏移 | 长度 | 值 | 描述 |
|---|---|---|---|
| 1000 | 1 | 05 | 索引个数,此处为有 5 个索引 |
| 1000 | 1 | 06 | 索引列数目,总共 5 个索引有 6 个索引列 |
本文详细解析了MySQL.frm文件的格式与结构,包括文件头部Header段和索引Key信息段的内容与含义,并通过实例创建的表来展示.frm文件的具体构成。
216

被折叠的 条评论
为什么被折叠?



