MySQL的数据存储并非简单的将表数据写入磁盘,而是依托存储引擎的架构设计,通过分层的结构实现高效的数据管理和读写。不同的存储引擎对应不同的存储逻辑,其中InnoDB是目前最常用的引擎,也是大多数生产环境的默认选择。

MySQL存储引擎与存储架构
MySQL支持多种存储引擎,不同引擎的数据存储方式差异很大,常见的存储引擎特性对比如下:
| 存储引擎 | 事务支持 | 外键支持 | 数据存储方式 |
|---|---|---|---|
| InnoDB | 支持 | 支持 | 表空间文件存储,支持行级锁 |
| MyISAM | 不支持 | 不支持 | 分文件存储.frm、.MYD、.MYI,表级锁 |
| Memory | 不支持 | 不支持 | 内存存储,重启后数据丢失 |
目前生产环境几乎都使用InnoDB引擎,因此后续内容主要围绕InnoDB的数据存储逻辑展开。
InnoDB核心存储结构
表空间
InnoDB的数据存储在表空间中,表空间是InnoDB逻辑存储的最高层,所有数据都存放在表空间内。表空间分为系统表空间和独立表空间两种模式:
- 系统表空间:默认情况下所有InnoDB表的数据都存放在系统表空间文件ibdata1中,文件会不断增大,难以单独回收某个表的空间。
- 独立表空间:通过配置
innodb_file_per_table=ON,每个表会生成独立的.ibd文件,表的数据和索引都存储在该文件中,删除表时可以直接回收磁盘空间。
段、区、页、行
表空间内部又分为多个层级的结构,从大到小依次为段、区、页、行:
- 段:分为数据段、索引段、回滚段等,数据段存放B+树的叶子节点数据,索引段存放B+树的非叶子节点数据。
- 区:每个区的大小固定为1MB,由64个连续的页组成,为了保证页的连续性,InnoDB每次从磁盘申请空间时都是以区为单位。
- 页:是InnoDB磁盘管理的最小单位,默认大小为16KB,常见的页类型有数据页、undo页、系统页等,数据页用来存储实际的行数据。
- 行:是MySQL存储的最小逻辑单位,InnoDB支持多种行格式,包括Compact、Redundant、Dynamic、Compressed,目前默认使用Dynamic行格式。
行格式结构
Dynamic行格式下,行的结构包含变长字段长度列表、NULL值列表、记录头信息、列数据四个部分,其中对于大字段(如TEXT、BLOB类型),如果字段长度超过页的一半,会将字段的实际数据存储在溢出页中,当前页只存储指向溢出页的指针,避免单个页被大字段占满。
索引与数据存储的关系
InnoDB的索引采用B+树结构,分为聚簇索引和非聚簇索引:
- 聚簇索引:InnoDB表必须有且只有一个聚簇索引,默认是主键索引,如果表没有定义主键,会选择一个唯一非空索引作为聚簇索引,如果没有这样的索引,会隐式生成一个6字节的row_id作为聚簇索引。聚簇索引的叶子节点存储的是整行数据,因此通过主键查询可以直接获取到行数据。
- 非聚簇索引:也就是二级索引,叶子节点存储的是索引列的值和对应的主键值,通过非聚簇索引查询时,需要先找到主键值,再回表查询聚簇索引获取整行数据。
以下是通过主键查询和非主键索引查询的伪代码示例:
-- 聚簇索引查询,直接命中叶子节点获取行数据 SELECT * FROM user WHERE id = 100; -- 非聚簇索引查询,先查索引获取主键,再回表查聚簇索引 SELECT * FROM user WHERE name = '张三';
常见数据存储问题
数据碎片问题
当表频繁进行删除、更新操作时,会产生数据碎片,因为InnoDB删除数据时不会立即回收磁盘空间,只是标记为可复用,导致.ibd文件大小远大于实际数据量。可以通过以下命令查看表的碎片情况:
-- 查看表的碎片率,Data_free为碎片空间大小 SHOW TABLE STATUS LIKE 'user';
如果碎片率过高,可以通过ALTER TABLE语句重建表来回收空间:
-- 重建表,回收碎片空间 ALTER TABLE user ENGINE=InnoDB;
大表存储优化
当单表数据量过大时,会影响查询性能,常见的优化方式包括:
- 分表:将大表拆分为多个小表,比如按时间范围拆分、按业务维度拆分。
- 分区:使用MySQL的分区功能,将表的数据按照规则分布到不同的分区中,查询时只扫描对应的分区,减少数据扫描量。
- 合理设计索引:避免冗余索引,尽量使用覆盖索引减少回表操作,降低IO消耗。
字符集对存储的影响
不同的字符集占用的存储空间不同,比如utf8mb4字符集下,一个普通字符占用3个字节,emoji表情占用4个字节,而latin1字符集下一个字符只占用1个字节。设计表结构时,需要根据实际存储的内容选择合适的字符集,避免不必要的空间浪费。
总结
MySQL的数据存储是一个分层设计的结构,从表空间到行层层递进,InnoDB通过B+树索引结构实现高效的数据查询,同时不同的存储配置会影响磁盘空间的利用率和查询性能。理解底层存储逻辑,有助于开发者在设计表结构、优化查询时做出更合理的选择,解决实际场景中遇到的存储相关的问题。