把总结写开头:
明天再写吧,上床睡觉。
一、数据库和文件系统的关系
-
InnoDB 、 MyISAM 这样的存储引擎都是把表存储在文件系统上的。当我们想读取数据的时候,这些存储引擎会从文件系统中把数据读出来返回给我们,当我们想写入数据的时候,这些存储引擎会把这些数据又写回文件系统。
二、MySQL数据目录
- MySQL服务器程序在启动时会到文件系统的某个目录下加载一些文件,之后在运行过程中产生的数据也都会存储到这个目录下的某些文件中,这个目录就称为
数据目录
。
1、数据目录和安装目录的区别
-
MySQL
的安装目录(在安装MySQL
的时候我们可以自己指定),我们重点强调过这个安装目录
下非常重要的bin
目录,它里边存储了许多关于控制客户端程序和服务器程序的命令(许多可执行文件,比如mysql
,mysqld
,mysqld_safe
等等等等好几十个)。 -
而
数据目录
是用来存储MySQL
在运行过程中产生的数据,一定要和本章要讨论的安装目录
区别开!一定要区分开!一定要区分开!一定要区分开!
2、如何确定MySQL中的数据目录
- 那说了半天,到底
MySQL
把数据都存到哪个路径下呢?其实数据目录
对应着一个系统变量datadir
,我们在使用客户端与服务器建立连接之后查看这个系统变量的值就可以了:
mysql> SHOW VARIABLES LIKE ‘datadir‘;
+---------------+-----------------------+
| Variable_name | Value |
+---------------+-----------------------+
| datadir | /usr/local/var/mysql/ |
+---------------+-----------------------+
1 row in set (0.00 sec)
- 从结果中可以看出,在我的计算机上
MySQL
的数据目录就是/usr/local/var/mysql/
三、数据目录的结构
-
MySQL
在运行过程中都会产生哪些数据呢?当然会包含我们创建的数据库、表、视图和触发器吧啦吧啦的用户数据,除了这些用户数据,为了程序更好的运行,MySQL
也会创建一些其他的额外数据,我们接下来细细的品味一下这个数据目录
下的内容。
1、数据库在文件系统中的表示
-
每当我们使用
CREATE DATABASE 数据库名
语句创建一个数据库的时候,在文件系统上实际发生了什么呢?其实很简单,每个数据库都对应数据目录下的一个子目录,或者说对应一个文件夹,我们每当我们新建一个数据库时,MySQL
会帮我们做这两件事儿:-
在
数据目录
下创建一个和数据库名同名的子目录(或者说是文件夹)。 -
在该与数据库名同名的子目录下创建一个名为
db.opt
的文件,这个文件中包含了该数据库的各种属性,比方说该数据库的字符集和比较规则是个啥。
-
-
比方说我们查看一下在我的计算机上当前有哪些数据库:
mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| charset_demo_db |
| dahaizi |
| mysql |
| performance_schema |
| sys |
| xiaohaizi |
+--------------------+
7 rows in set (0.00 sec)
可以看到在我的计算机上当前有7个数据库,其中charset_demo_db
、dahaizi
和xiaohaizi
数据库是我们自定义的,其余4个数据库是属于MySQL自带的系统数据库。我们再看一下我的计算机上的数据目录
下的内容:
.
├── auto.cnf
├── ca-key.pem
├── ca.pem
├── charset_demo_db
├── client-cert.pem
├── client-key.pem
├── dahaizi
├── ib_buffer_pool
├── ib_logfile0
├── ib_logfile1
├── ibdata1
├── ibtmp1
├── mysql
├── performance_schema
├── private_key.pem
├── public_key.pem
├── server-cert.pem
├── server-key.pem
├── sys
├── xiaohaizideMacBook-Pro.local.err
├── xiaohaizideMacBook-Pro.local.pid
└── xiaohaizi
6 directories, 16 files
当然这个数据目录下的文件和子目录比较多哈,但是如果仔细看的话,除了information_schema
这个系统数据库外,其他的数据库在数据目录
下都有对应的子目录。这个information_schema
比较特殊。
2、表在文件系统中的表示
-
我们的数据其实都是以记录的形式插入到表中的,每个表的信息其实可以分为两种:
- 表结构的定义
- 表中的数据
-
表结构
就是该表的名称是啥,表里边有多少列,每个列的数据类型是啥,有啥约束条件和索引,用的是啥字符集和比较规则吧啦吧啦的各种信息,这些信息都体现在了我们的建表语句中了。为了保存这些信息,InnoDB
和MyISAM
这两种存储引擎都在数据目录
下对应的数据库子目录下创建了一个专门用于描述表结构的文件,文件名是这样:
表名.frm
- 比方说我们在
dahaizi
数据库下创建一个名为test
的表:
mysql> USE dahaizi;
Database changed
mysql> CREATE TABLE test (
-> c1 INT
-> );
Query OK, 0 rows affected (0.03 sec)
- 那在数据库
dahaizi
对应的子目录下就会创建一个名为test.frm
的用于描述表结构的文件。值得注意的是,这个后缀名为.frm是以二进制格式存储的
(1)InnoDB是如何存储表数据的
前边重点唠叨过InnoDB
的一些实现原理,到现在为止我们应该熟悉下边这些东东:
-
InnoDB
其实是使用页
为基本单位来管理存储空间的,默认的页
大小为16KB
。 -
对于
InnoDB
存储引擎来说,每个索引都对应着一棵B+
树,该B+
树的每个节点都是一个数据页,数据页之间不必要是物理连续的,因为数据页之间有双向链表
来维护着这些页的顺序。 -
InnoDB
的聚簇索引的叶子节点存储了完整的用户记录,也就是所谓的索引即数据,数据即索引。 -
为了更好的管理这些页,设计
InnoDB
的大叔们提出了一个表空间
或者文件空间
(英文名:table space
或者file space
)的概念,这个表空间是一个抽象的概念,它可以对应文件系统上一个或多个真实文件(不同表空间对应的文件数量可能不同)。每一个表空间
可以被划分为很多很多很多个页
,我们的表数据就存放在某个表空间
下的某些页里。设计InnoDB
的大叔将表空间划分为几种不同的类型,我们一个一个看一下。
(2)系统表空间(system tablespace)
-
这个所谓的
系统表空间
可以对应文件系统上一个或多个实际的文件,默认情况下,InnoDB
会在数据目录
下创建一个名为ibdata1
(在你的数据目录下找找看有木有)、大小为12M
的文件,这个文件就是对应的系统表空间
在文件系统上的表示。怎么才12M
?这么点儿还没插多少数据就用完了,哈哈,那是因为这个文件是所谓的自扩展文件
,也就是当不够用的时候它会自己增加文件大小~ -
当然,如果你想让系统表空间对应文件系统上多个实际文件,或者仅仅觉得原来的
ibdata1
这个文件名难听,那可以在MySQL
启动时配置对应的文件路径以及它们的大小,比如我们这样修改一下配置文件:
[server]
innodb_data_file_path=data1:512M;data2:512M:autoextend
- 这样在
MySQL
启动之后就会创建这两个512M大小的文件作为系统表空间
,其中的autoextend
表明这两个文件如果不够用会自动扩展data2
文件的大小。
在一个MySQL服务器中,系统表空间只有一份
(3)独立表空间(file-per-table tablespace)
- 在MySQL5.6.6以及之后的版本中,
InnoDB
并不会默认的把各个表的数据存储到系统表空间中,而是为每一个表建立一个独立表空间,也就是说我们创建了多少个表,就有多少个独立表空间。使用独立表空间
来存储表数据的话,会在该表所属数据库对应的子目录下创建一个表示该独立表空间
的文件,文件名和表名相同,只不过添加了一个.ibd
的扩展名而已,所以完整的文件名称长这样:
表名.ibd
- 比方说假如我们使用了
独立表空间
去存储xiaohaizi
数据库下的test
表的话,那么在该表所在数据库对应的xiaohaizi
目录下会为test
表创建这两个文件:
test.frm
test.ibd
- 其中
test.ibd
文件就用来存储test
表中的数据和索引。当然我们也可以自己指定使用系统表空间
还是独立表空间
来存储数据,这个功能由启动参数innodb_file_per_table
控制,比如说我们想刻意将表数据都存储到系统表空间
时,可以在启动MySQL
服务器的时候这样配置:
[server]
innodb_file_per_table=0
当innodb_file_per_table
的值为0
时,代表使用系统表空间;当innodb_file_per_table
的值为1
时,代表使用独立表空间。不过innodb_file_per_table
参数只对新建的表起作用,对于已经分配了表空间的表并不起作用。如果我们想把已经存在系统表空间中的表转移到独立表空间,可以使用下边的语法:
ALTER TABLE 表名 TABLESPACE [=] innodb_file_per_table;
或者把已经存在独立表空间的表转移到系统表空间,可以使用下边的语法:
ALTER TABLE 表名 TABLESPACE [=] innodb_system;
其中中括号扩起来的=
可有可无,比方说我们想把test
表从独立表空间移动到系统表空间,可以这么写:
ALTER TABLE test TABLESPACE innodb_system;
(4)其他类型的表空间
随着MySQL的发展,除了上述两种老牌表空间之外,现在还新提出了一些不同类型的表空间,比如通用表空间(general tablespace)、undo表空间(undo tablespace)、临时表空间(temporary tablespace)吧啦吧啦的,具体情况我们就不细唠叨了,等用到的时候再提。