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 个索引列 |