一、引言
1、MySQL数据存放在哪个文件?
创建一个数据库会产生三种格式的文件,分别是.opt格式、.frm格式、.ibd格式。
opt格式:用来存储当前数据库的默认字符集和字符校验规则。
frm格式:该文件是用来保存每个表的元数据信息的,主要包含表结构定义。
ibd格式:存放数据库的数据
2、表空间文件的结构是什么样的?
表空间由段(segment)、区(extent)、页(page)、行(row)组成
行:数据库表的记录都是按行进行存放的,每行记录根据不同行格式,有不同的存储结构。
页:InnoDB 的数据是按「页」为单位来读写的,每页大小默认16k
区:在表中数据量大的时候,为某个索引分配空间的时候就不再按照页为单位分配了,而是按照区为单位分配。每个区的大小为 1MB,对于 16KB 的页来说,连续的 64 个页会被划为一个区,这样就使得链表中相邻的页的物理位置也相邻,就能使用顺序 I/O 了。
段:表空间是由各个段组成的,段是由多个区组成的。可分为数据段、索引段和回滚段等。
二、innodb的compact行格式
innodb的compact的行格式,如下所示
可以看到行格式可以分为记录的额外信息和记录的真实数据,记录的真实数据就不再赘述了,就是记录真实的存放的数据,但是还存放三个隐藏列:row_id, trx_id, roll_pointer!
记录的额外信息分为:记录头信息、NULL值列表、变长字段长度列表
记录头信息:里面有delete_mask(标记是否被删除)、next_record(标记下一条记录的位置)、record_type(表示当前记录类型)。
NULL列表:如果存在允许 NULL 值的列,则每个列对应一个二进制位,二进制位按照列的顺序逆序排列。如果NULL值列大于8个,就需要两个字节存储
变长字段长度列表:在存储数据的时候,也要把数据占用的大小存起来,存到变长字段长度列表里面,读取数据的时候才能根据它去读取对应长度的数据。其他 TEXT、BLOB 等变长字段也是这么实现的。
三、行溢出后,MySQL是怎么处理的
MySQL 中磁盘和内存交互的基本单位是页,一个页的大小一般是 16KB
,也就是 16384字节
,而一个 varchar(n) 类型的列最多可以存储 65532字节
,一些大对象如 TEXT、BLOB 可能存储更多的数据,这时一个页可能就存不了一条记录。这个时候就会发生行溢出,多的数据就会存到另外的溢出页中。 然后会在行中用20个字节来存储溢出页的地址!
四、一些问题的回答
MySQL 的 NULL 值是怎么存放的?
MySQL 的 Compact 行格式中会用NULL值列表来标记值为 NULL 的列,NULL 值并不会存储在行格式中的真实数据部分。NULL值列表会占用 1 字节空间,当表中所有字段都定义成 NOT NULL,行格式中就不会有 NULL值列表,这样可节省 1 字节的空间。
MySQL 怎么知道 varchar(n) 实际占用数据的大小?
MySQL的compact格式会有一个变长字段列表进行存储实际占用数据的大小
varchar(n) 中 n 最大取值为多少?
最大取值为65535-NULL值列表占用字节数-变长字段长度列表所占字节数
行溢出后,MySQL 是怎么处理的?
Compact 行格式针对行溢出的处理是这样的:当发生行溢出时,在记录的真实数据处只会保存该列的一部分数据,而把剩余的数据放在溢出页中,然后真实数据处用 20 字节存储指向溢出页的地址,从而可以找到剩余数据所在的页。