封面来源:由博主个人绘制,如需使用请联系博主。

本文参考:MySQL数据库教程天花板,mysql安装到mysql高级,强!硬!

1. MySQL 8.0 的主要目录结构

在 Linux 环境下执行以下命令,查询系统中与 MySQL 相关的文件:

1
find / -name mysql
[root@mofan ~]# find / -name mysql
/var/lib/mysql
/var/lib/mysql/mysql
/usr/lib64/mysql
/usr/bin/mysql
/opt/mysql
/etc/logrotate.d/mysql

1.1 数据库文件的存放路径

MySQL 数据库文件的存放路径:/var/lib/mysql

MySQL 服务器程序在启动时会到文件系统的某个目录下加载一些文件,之后在运行过程中产生的数据也会存储到这个目录下的某些文件中,这个目录被称为 数据目录

MySQL 把数据都存到哪个路径下呢?数据目录 对应着一个系统变量 datadir,在客户端与服务器建立连接后查看这个系统变量:

1
show variables like 'datadir';
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| datadir       | /var/lib/mysql/ |
+---------------+-----------------+

1.2 相关指令目录

MySQL 相关指令存放的目录有两个:

  • /usr/bin:存放 mysqladminmysqlbinlogmysqldump 等命令
  • /usr/sbin
[root@mofan ~]# cd /usr/bin
[root@mofan bin]# find . -name "mysqladmin"
./mysqladmin
[root@mofan bin]# find . -name "mysqldump"
./mysqldump

bin 目录下存放了很多关于控制客户端程序和服务器程序的命令(许多可执行文件,比如 mysqlmysqldmysqld_safe 等),而前文介绍的 数据目录 是用来存储 MySQL 在运行过程中产生的数据,注意区分二者。

1.3 配置文件目录

MySQL 配置文件的存放目录也有两个:

  • /usr/share/mysql-8.0:存放相关命令及配置文件
  • /etc:配置文件 my.cnf 的存放位置

2. 数据库和文件系统的关系

InnoDBMyISAM 这样的存储引擎都是把表存储在磁盘上的,操作系统用来管理磁盘的结构被称为 文件系统,所以用专业一点的话来表述就是:像 InnoDBMyISAM 这样的存储引擎都是把表存储在文件系统上的。当需要读取数据的时候,这些存储引擎会从文件系统中把数据读出来并返回;当需要写入数据的时候,这些存储引擎会把这些数据又写回文件系统。

2.1 查看默认数据库

MySQL 在安装完毕后会自带几个系统数据库,执行以下语句查看 MySQL 有几个自带的系统数据库:

1
SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+

mysql

MySQL 系统自带的核心数据库,它存储了 MySQL 的用户账户和权限信息,一些存储过程、事件的定义信息,一些运行过程中产生的日志信息,一些帮助信息以及时区信息等。

information_schema

MySQL 系统自带的数据库,这个数据库保存着 MySQL 服务器维护的所有其他数据库的信息,比如有哪些表、哪些视图、哪些触发器、哪些列、哪些索引。这些信息并不是真实的用户数据,而是一些描述性信息,有时候也称之为元数据。在系统数据库 information_schema 中提供了一些以 innodb_sys 开头的表,用于表示内部系统表。

1
2
USE information_schema;
SHOW TABLES LIKE 'innodb_sys%';

performance_schema

MySQL 系统自带的数据库,这个数据库里主要保存 MySQL 服务器运行过程中的一些状态信息,可以用来监控 MySQL 服务的各类性能指标。包括统计最近执行了哪些语句,在执行过程的每个阶段都花费了多长时间,内存的使用情况等信息。

sys

MySQL 系统自带的数据库,这个数据库主要是通过视图的形式把 information_schema 和 performance_schema 结合起来,帮助系统管理员和开发人员监控 MySQL 的技术性能。

2.2 数据库在文件系统中的表示

使用 CREATE DATABASE 数据库名; 语句创建一个数据库时,在文件系统上发生了什么呢?其实很简单,每个数据库都对应了数据目录下的一个子目录,或者说对应一个文件夹,每当新建一个数据库时,MySQL 会做两件事:

  1. 数据目录 下创建一个和数据库同名的子目录;
  2. 在与该数据库同名的子目录下创建一个名为 db.opt 的文件(仅限 MySQL 5.7 及之前的版本),这个文件中包含了 该数据库的各种属性信息,比如该数据库使用的字符集和比较规则。

进入 MySQL 8.0 的 数据目录 并查看目录中的文件信息:

1
2
cd /var/lib/mysql
ll
[root@mofan /]# cd /var/lib/mysql
[root@mofan mysql]# ll
total 90584
-rw-r----- 1 mysql mysql       56 Feb 13 18:18 auto.cnf
-rw-r----- 1 mysql mysql      502 Feb 13 18:52 binlog.000001
-rw-r----- 1 mysql mysql     6604 Feb 26 19:22 binlog.000002
-rw-r----- 1 mysql mysql       32 Feb 13 18:52 binlog.index
-rw------- 1 mysql mysql     1676 Feb 13 18:18 ca-key.pem
-rw-r--r-- 1 mysql mysql     1112 Feb 13 18:18 ca.pem
-rw-r--r-- 1 mysql mysql     1112 Feb 13 18:18 client-cert.pem
-rw------- 1 mysql mysql     1676 Feb 13 18:18 client-key.pem
drwxr-x--- 2 mysql mysql     4096 Feb 26 19:17 dbtest1
-rw-r----- 1 mysql mysql   196608 Feb 26 19:22 #ib_16384_0.dblwr
-rw-r----- 1 mysql mysql  8585216 Feb 13 18:18 #ib_16384_1.dblwr
-rw-r----- 1 mysql mysql     3525 Feb 13 18:52 ib_buffer_pool
-rw-r----- 1 mysql mysql 12582912 Feb 26 19:22 ibdata1
-rw-r----- 1 mysql mysql 12582912 Feb 13 18:52 ibtmp1
drwxr-x--- 2 mysql mysql     4096 Feb 13 18:52 #innodb_redo
drwxr-x--- 2 mysql mysql     4096 Feb 13 18:52 #innodb_temp
drwxr-x--- 2 mysql mysql     4096 Feb 13 18:18 mysql
-rw-r----- 1 mysql mysql 25165824 Feb 26 19:17 mysql.ibd
srwxrwxrwx 1 mysql mysql        0 Feb 13 18:52 mysql.sock
-rw------- 1 mysql mysql        5 Feb 13 18:52 mysql.sock.lock
drwxr-x--- 2 mysql mysql     4096 Feb 13 18:18 performance_schema
-rw------- 1 mysql mysql     1676 Feb 13 18:18 private_key.pem
-rw-r--r-- 1 mysql mysql      452 Feb 13 18:18 public_key.pem
-rw-r--r-- 1 mysql mysql     1112 Feb 13 18:18 server-cert.pem
-rw------- 1 mysql mysql     1680 Feb 13 18:18 server-key.pem
drwxr-x--- 2 mysql mysql     4096 Feb 13 18:18 sys
-rw-r----- 1 mysql mysql 16777216 Feb 26 19:18 undo_001
-rw-r----- 1 mysql mysql 16777216 Feb 26 19:22 undo_002

这个数据目录下的文件和子目录比较多,除 information_schema 这个系统数据库外,其他的数据库在数据目录下都有对应的子目录。

dbtest1 数据库为例:

1
2
cd dbtest1/
ll
[root@mofan mysql]# cd dbtest1/
[root@mofan dbtest1]# ll
total 224
-rw-r----- 1 mysql mysql 114688 Feb 19 17:27 emp1.ibd
-rw-r----- 1 mysql mysql 114688 Feb 26 19:22 mytbl2.ibd

2.3 InnoDB存储引擎模式

用户的数据都是以 记录的形式 插入到表中的,每个表的信息可以分为两种:

  1. 表结构的定义
  2. 表中的数据

表结构 就是该表的名称,表中有多少列,每个列的数据类型、约束条件和索引,使用的字符集和比较规则等各种信息,这些信息都会体现在建表语句中。

表结构

为了保存表结构,InnoDB 在数据目录下对应的数据库子目录下创建了一个专门用于描述表结构的文件,文件名类似于 表名.frm

比方说在 dbtest1 数据库下创建一个名为 test 的表:

1
CREATE TABLE test(c1 INT);

那在数据库 dbtest1 对应的子目录下就会创建一个名为 test.frm 的用于描述表结构的文件。.frm 文件的格式在不同的平台上都是相同的,该文件内容以二进制格式存储的,直接打开看到的内容乱码。

表中数据和索引

InnoDB 使用 为基本单位来管理存储空间的, 的默认大小为 16KB。

对于 InnoDB 存储引擎来说,每个索引都对应着一颗 B+ 树,B+ 树的每个节点都是一个数据页,数据页之间不需要是物理连续的,因为数据页之间有 双向链表 来维护着这些页的顺序。

InnoDB 的聚簇索引的叶子节点存储了完整的用户记录,也就是所谓的“索引即数据,数据即索引”。

为了更好地管理这些页,InnoDB 提出了一个 表空间(table space)文件空间(file space) 的概念,表空间是一个抽象的概念,它可以对应文件系统上一个或多个真实文件(不同表空间对应的文件数量可能不同)。每一个 表空间 可以被划分为多个页,数据表中的数据就存放在某个 表空间 下的某些页里。

表空间有几种不同的类型:

  1. 系统表空间(system tablespace)
  2. 独立表空间(file-per-table tablespace)
  3. 其他类型的表空间

① 系统表空间

默认情况下,InnoDB 会在数据目录下创建一个名为 ibdata1、大小为 12M 的文件,这个文件就是对应的系统表空间在文件系统上的表示。

怎么才 12M?这个文件是自扩展文件,当不够用的时候它会自己增加文件大小。

如果想让系统表空间对应文件系统上多个实际文件,或者仅仅觉得默认的 ibdata1 文件名难听,那么在 MySQL 启动时可以配置对应的文件路径以及它们的大小,比如这样修改 my.cnf 配置文件:

1
2
[server]
innodb_data_file_path=data1:512M;data2:512M:autoextend

这样在 MySQL 启动之后就会创建两个 512M 大小的文件作为系统表空间,其中的 autoextend 属性表示当这两个文件大小不够用时就会自动拓展 data2 文件的大小。

需要注意的是,在一个 MySQL 服务器中,系统表空间只有一份。从 MySQL 5.5.7 到 MySQL 5.6.6 之间的各个版本中,表中的数据都会被默认地存储到这个系统表空间中。

② 独立表空间

在 MySQL 5.6.6 以及之后的版本中,InnoDB 并不会默认的把各个表的数据存储到系统表空间中,而是为每一个表建立一个独立表空间,即创建了多少个表,就有多少个独立表空间。使用独立表空间来存储表数据的话,会在该表所属数据库对应的子目录下创建一个表示该独立表空间的文件,文件名和表名相同,扩展名为 .ibd,类似于 表名.ibd

比如使用了独立表空间去存储 dbtest1 数据库下的 test 表的话,那么在该表所在数据库对应的 dbtest1 目录下会为 test 表创建 test.frmtest.ibd 两个文件。其中 test.ibd 文件用来存储 test 表中的数据和索引。

③ 系统表空间与独立表空间的设置

可以指定使用系统表空间还是独立表空间来存储数据,这个功能由启动参数 innodb_file_per_table 控制,比如想刻意地将表数据都存储到系统表空间时,可以这样修改 my.cnf 配置文件:

1
2
[server]
innodb_file_per_table=0 # 0 代表使用系统表空间; 1 代表使用独立表空间

执行以下语句查看默认情况下的配置:

1
show variables like 'innodb_file_per_table';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | ON    |
+-----------------------+-------+

其中的 ON 表示默认情况下使用独立表空间存放表数据。

innodb_file_per_table 参数的修改只对新建的表起作用,对于已经分配了表空间的表并不起作用。

如果想把已经存在系统表空间中的表转移到独立表空间中,可以执行以下语句:

1
ALTER TABLE 表名 TABLESPACE [=] innodb_file_per_table;

或者把已经存在独立表空间的表转移到系统表空间中,可以执行以下语句:

1
ALTER TABLE 表名 TABLESPACE [=] innodb_system;

其中中括号括起来的 = 可以省略。

④ 其他类型的表空间

随着 MySQL 的发展,除了上述两种老牌表空间之外,现在还新提出了一些不同类型的表空间,比如通用表空间(general tablespace)、临时表空间(temporary tablespace)等。

疑问

frm 文件在 MySQL 8.0 中不存在了,那去哪里了呢?

这就需要解析 ibd 文件了,Oracle 官方将 frm 文件的信息及更多的信息移动到序列化字典信息(Serialized Dictionary Information)中,SDI 被写在 ibd 文件内部,MySQL 8.0 也属于 Oracle 旗下,因此同理。

为了从 ibd 文件中提取 SDI 信息,Oracle 提供了一个应用程序 ibd2sdi。这个工具不需要下载,MySQL 8.0 自带就有。

① 查看表结构:到存储 ibd 文件的目录下,执行以下语句:

1
ibd2sdi --dump-file=emp1.txt emp1.ibd
[root@mofan dbtest1]# ibd2sdi --dump-file=emp1.txt emp1.ibd
[root@mofan dbtest1]# ls
emp1.ibd  emp1.txt  mytbl2.ibd

执行完毕后,可以看到多出 emp1.txt 文件。查看该文件内容,就能看到 emp1 表的表结构。

2.4 MyISAM存储引擎模式

表结构

在存储表结构方面,MyISAM 和 InnoDB 一样,也是在数据目录下对应的数据库子目录中创建了一个专门用于描述表结构的文件 表名.frm

表中的数据和索引

在 MyISAM 中的索引全部都是二级索引,该存储引擎的数据和索引是分开存放的。所以在文件系统中也是使用不同的文件来存储数据文件和索引文件,同时表数据都存放在对应的数据库子目录下。假如 test 表使用 MyISAM 存储引擎的话,那么在它所在数据库对应的 dbtest1 目录下会为 test 表创建这三个文件:

  • test.frm:存储表结构
  • test.MYD:存储数据(MYData),采用独立表存储模式,每个表对应一个 MYD 文件
  • test.MYI:存储索引(MYIndex)

比如,创建一个使用 MyISAM 作为存储引擎的表,使用 ENGINE 选项显式指定引擎,因为默认引擎是 InnoDB:

1
2
3
4
5
6
7
CREATE TABLE `student_myisam` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(64) DEFAULT NULL,
`age` int DEFAULT NULL,
`sex` varchar(2) DEFAULT NULL,
PRIMARY KEY (`id`)
)ENGINE=MYISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb3;

在 MySQL 8.0 下,成功新建 student_myisam 表后,在数据目录下新增三个文件:

  • student_myisam_367.sdi:存储元数据

  • student_myisam.MYD:存储数据

  • student_myisam.MYI:存储索引

对于采用 InnoDB 存储引擎的表,SDI 与独立表空间下的用户数据一起存储;对于采用 MyISAM 存储引擎的表,它被写入 sdi 文件中。

在 MySQL 8.0 中,MyISAM 存储引擎不提供分区支持。在以前版本的 MySQL 中创建的分区 MyISAM 表不能在 MySQL 8.0 中使用。

2.5 小结

以数据库 a 中的数据表 b 为例。

如果表 b 采用 InnoDB

data\a 中会产生 1 个或者 2 个文件:

  • b.frm:描述表结构文件,字段长度等
  • 如果采用 系统表空间 模式,数据信息和索引信息都存储在 ibdata1
  • 如果采用 独立表空间 存储模式,data\a 中还会产生 b.ibd 文件(存储数据信息和索引信息)

不同的 MySQL 版本下也有区别:

  • MySQL 5.7 中会在 data/a 目录下生成 db.opt 文件用于保存数据库的相关配置,比如字符集、比较规则等信息,而 MySQL 8.0 不再提供 db.opt 文件。
  • MySQL 8.0 中不再单独提供 b.frm,而是合并在 b.ibd 文件中。

如果表 b 采用 MyISAM

data\a 中会产生 3 个文件:

  • MySQL 5.7 下生成 b.frm,用于描述表结构文件,字段长度等;MySQL 8.0 下生成 b.xxx.sdi,描述表结构文件,字段长度等
  • b.MYD(MYData):数据信息文件,存储数据信息(如果采用独立表存储模式)
  • b.MYI(MYIndex):存放索引信息文件

2.6 视图在文件系统中的表示

MySQL 中的视图其实是虚拟的表,也就是某个查询语句的一个别名而已,所以在存储视图的时候不需要存储真实的数据,只需要把它的结构存储起来就行了。

和表一样,描述视图结构的文件也会被存储到所属数据库对应的子目录下边,只会存储一个 视图名.frm 的文件。

2.7 其他的文件

除了前文说的那些用户自己存储的数据以外,数据目录下还包括为了更好地运行程序的一些额外文件,主要包括这几类文件:

  • 服务器进程文件:每运行一个 MySQL 服务器程序,都意味着启动一个进程。MySQL 服务器会把自己的进程 ID 写入到一个文件中
  • 服务器日志文件:在服务器运行过程中,会产生各种各样的日志,比如常规的查询日志、错误日志、二进制日志、redo 日志等
  • 默认/自动生成的 SSL 和 RSA 证书和密钥文件:主要是为了客户端和服务器安全通信而创建的一些文件