浅谈MySQL 中的 “数据库” 和 “表” 在磁盘上的存储机制

90 阅读4分钟

以最常用的 InnoDB 存储引擎为例进行说明。

一、核心概念:表空间 (Tablespace)

在 InnoDB 中,数据并非简单地以单个文件对应单个表,而是存储在表空间中。表空间是 InnoDB 存储数据的逻辑容器。

InnoDB 表空间的两种模式

  1. 系统表空间 (System Tablespace)

    • 文件:通常是一个或多个名为 ibdata1, ibdata2, ... 的文件,位于 MySQL 数据目录下(如 /var/lib/mysql/)。
    • 存储内容
      • InnoDB 系统信息(如数据字典)。
      • 双写缓冲区 (Doublewrite Buffer)变更缓冲区 (Change Buffer)
      • 所有 InnoDB 表的数据和索引(如果未启用独立表空间)。
    • 特点:所有表的数据都挤在一个或少数几个大文件里。缺点是无法单独收缩某个表的空间,且 ibdata1 文件会不断增长,难以管理。
  2. 独立表空间 (File-Per-Table Tablespace)

    • 文件:每个 InnoDB 表对应一个独立的 .ibd 文件。
    • 文件位置:位于对应数据库的目录下(如 /var/lib/mysql/mydb/mytable.ibd)。
    • 存储内容仅包含该表的数据和索引
    • 配置:通过 MySQL 配置参数 innodb_file_per_table = ON 启用(现代 MySQL 版本默认开启)。
    • 优点
      • 空间管理灵活:可以 TRUNCATEDROP 表来释放磁盘空间。
      • 可以对单个表进行优化(如 OPTIMIZE TABLE)。
      • 便于表的传输和备份。

总结:现代 MySQL 部署强烈推荐使用独立表空间模式innodb_file_per_table = ON)。


二、“数据库”在磁盘上的体现

在 MySQL 中,“数据库”本质上是一个命名空间目录

  • 物理存储
    • 当你创建一个数据库(CREATE DATABASE mydb;)时,MySQL 会在其数据目录datadir,可通过 SHOW VARIABLES LIKE 'datadir'; 查看)下创建一个同名的文件夹
    • 例如:/var/lib/mysql/mydb/
  • 该文件夹内包含
    • 该数据库下所有.ibd 文件(在独立表空间模式下)。
    • 其他相关文件,如 .frm 文件(在 MySQL 8.0 之前,存储表的结构定义,即元数据)。
    • 在 MySQL 8.0 及以后版本,表结构信息(数据字典)被集成到 InnoDB 的系统表空间中,不再使用 .frm 文件。

简单说一个 MySQL 数据库 ≈ 一个操作系统上的文件夹


三、“表”在磁盘上的体现

InnoDB + 独立表空间 模式为例:

  1. 数据和索引文件

    • 每个 InnoDB 表对应一个 .ibd 文件。
    • 文件名表名.ibd(如 users.ibd)。
    • 位置:位于其所属数据库的文件夹内(如 /var/lib/mysql/mydb/users.ibd)。
    • 内容:该文件包含了表的所有数据行所有索引(包括主键索引、二级索引等)。InnoDB 使用 B+ 树 结构在 .ibd 文件中组织数据。
  2. 表结构定义文件 (MySQL 5.7 及更早版本)

    • 每个表还有一个 .frm 文件(如 users.frm)。
    • 内容:存储表的元数据,如列名、数据类型、约束、字符集等。
    • 位置:同样在数据库文件夹内。
  3. MySQL 8.0 的变化

    • 引入了数据字典 (Data Dictionary)
    • 表结构信息不再存储在 .frm 文件中,而是统一存储在 InnoDB 的系统表空间ibdata 文件)的内部系统表中。
    • 因此,MySQL 8.0 不再生成 .frm 文件

四、其他存储引擎的存储方式(简要)

  • MyISAM

    • 每个表有三个文件:
      • .frm:表结构定义。
      • .MYD (MYData):存储数据。
      • .MYI (MYIndex):存储索引。
    • 位于数据库文件夹内。
  • Memory

    • 数据存储在内存中,不持久化到磁盘
    • 只有 .frm 文件(或 MySQL 8.0 的数据字典条目)描述表结构。

五、总结:磁盘存储结构图示

假设 MySQL 数据目录为 /var/lib/mysql/,使用 InnoDB + 独立表空间 + MySQL 8.0:

/var/lib/mysql/                  # MySQL 数据目录 (datadir)
├── ibdata1                      # InnoDB 系统表空间 (含数据字典、双写缓冲等)
├── ib_logfile0, ib_logfile1     # InnoDB 重做日志文件
├── mysql/                       # 系统数据库文件夹
│   ├── user.ibd                 # mysql.user 表的数据文件
│   └── ...                      # 其他系统表
├── performance_schema/          # performance_schema 数据库文件夹
│   └── ...                      # 各表的 .ibd 文件
├── mydb/                        # 你的数据库 "mydb" 文件夹
│   ├── users.ibd                # mydb.users 表的数据和索引文件
│   ├── orders.ibd               # mydb.orders 表的数据和索引文件
│   └── products.ibd             # mydb.products 表的数据和索引文件
└── ...                          # 其他数据库文件夹

核心要点

  • 数据库 = 文件夹
  • InnoDB 表 (8.0+) = 一个 .ibd 文件 (包含数据和索引) + 数据字典中的元数据
  • 独立表空间是现代最佳实践,便于管理和优化。
  • 日志文件(如 ib_logfile*, binlog, redo log)也存储在数据目录或指定位置,对数据持久性和恢复至关重要。