MySQL怎么存储一行记录
数据存放在哪个文件
查看数据保存路径。每个数据库都会在这个目录下,以数据库名创建一个子目录。
mysql> SHOW VARIABLES LIKE 'datadir';
+---------------+---------------------------------------------+
| Variable_name | Value |
+---------------+---------------------------------------------+
| datadir | D:\NewSoftware\MySQL\MySQL Server 5.6\data\ |
+---------------+---------------------------------------------+
1 row in set (0.00 sec)
数据库目录下保存了什么?
表名.frm:存储某表结构。
表名.ibd:存储某表数据。也称为
独占表空间
db.opt:用来存储当前数据库的默认字符集和字符校验规则。
表空间的结构
- 行:每条记录以行的格式存放
- 页:最小读取单位,InnoDB每次从磁盘中读取一页的数据到内存。默认页大小16KB。
- 区:在表中数据量大的时候,为某个索引分配空间的时候就不再按照页为单位分配了,而是按照区(extent)为单位分配。每个区的大小为 1MB,对于 16KB 的页来说,连续的 64 个页会被划为一个区,这样就使得链表中相邻的页的物理位置也相邻,就能使用顺序 I/O 了。
- 段:分为以下段
- 索引段:存放 B + 树的非叶子节点的区的集合;
- 数据段:存放 B + 树的叶子节点的区的集合;
- 回滚段:存放的是回滚数据的区的集合
InnoDB行格式
行格式(row_format),就是一条记录的存储结构。
InnoDB提供了Redundant(不够紧凑、已废弃)、Compact(较为紧凑,5.1版本后默认格式)、Dynamic(Compact的改进,5.7版本后默认行格式)和 Compressed(Compact改进) 行格式。
Compact行格式
额外信息
- 变长字段长度列表
对于VARCHAR、TEXT、BLOB等变长字段需要保存他们真实数据的占用的长度(字节数),之后读取时读取对应长度的数据即可。
需要注意存储长度的列表是逆序的。如【列2长度,列1长度】…列1值,列2值。
为什么这样设计?
首先【记录头信息】中有指向下一条记录的指针,指向的是下一条记录的【记录头信息】和【真实数据】之间的位置。这样的好处是向左读就是记录头信息,向右读就是真实数据。
逆序目的是使得位置靠前的记录的真实数据和数据对应的字段长度信息可以同时在一个 CPU Cache Line 中,这样就可以提高 CPU Cache 的命中率。
同理NULL值列表也是逆序的!
- NULL值列表
如果某个列允许设置为NULL值,那它对应一个二进制位,1表示该列的值为NULL,0表示该列值不为NULL。
因为NULL值列表存储单位是一个字节,所以当二进制位个数不足时,高位补0。
注意:上面两个列表不是必须要有的。当【没有变长字段|每个字段都不允许为NULL】,那么就没有对应的列表。
- 记录头信息
- delete_mask :标识此条数据是否被删除。从这里可以知道,我们执行 detele 删除记录的时候,并不会真正的删除记录,只是将这个记录的 delete_mask 标记为 1。
- next_record:下一条记录的位置。从这里可以知道,记录与记录之间是通过链表组织的。在前面我也提到了,指向的是下一条记录的「记录头信息」和「真实数据」之间的位置,这样的好处是向左读就是记录头信息,向右读就是真实数据,比较方便。
- record_type:表示当前记录的类型,0表示普通记录,1表示B+树非叶子节点记录,2表示最小记录,3表示最大记录
真实数据
- row_id:无主键,无唯一约束时就有该字段。非必需,占6字节
- trx_id:事务ID,表改数据由哪个事务生成。必需,占6字节。
- roll_pointer:记录上版本指针。必需,占7字节。