表空间的选择,能够说是对表的平常管理以及访问性能有很是紧密的联系。html
表空间是用来管理 MySQL 关系表的一种形式,有本身的磁盘文件。mysql
MySQL 表空间可分为共享表空间和单表空间;其中共享表空间又可分为系统表空间和通用表空间。sql
下面我来逐一看下每种表空间的相关特性。数据库
在 MySQL 数据目录下有一个名为 ibdata1 的文件,能够保存一张或者多张表。性能
923275 12M -rw-r----- 1 mysql mysql 12M 3月 18 10:42 ibdata1
这个文件就是 MySQL 的系统表空间文件,默认为 1 个,能够有多个,只须要在配置文件 my.cnf 里面这样定义便可。优化
innodb_data_file_path=ibdata1:200M;ibdata2:200M:autoextend:max:800Mspa
系统表空间不只能够是文件系统组成的文件,也能够是非文件系统组成的磁盘块,好比裸设备,定义也很简单日志
innodb_data_file_path=/dev/nvme0n1p1:3Gnewraw;/dev/nvme0n1p2:2Gnewrawcode
具体内容包括:double writer buffer、 change buffer、数据字典(MySQL 8.0 以前)、表数据、表索引。regexp
究其缘由,系统表空间有三个最大的缺点:
即便它包含的表都被删掉,这部分空间也不会自动释放。
举个例子:
# 表 t1 mysql> create table t1(id int, r1 char(36)) tablespace innodb_system; Query OK, 0 rows affected (0.03 sec) # ibdata1 初始大小为 12M mysql> \! ls -sihl ibdata1 923275 12M -rw-r----- 1 mysql mysql 12M 3月 18 15:32 ibdata1 # ... 插入一部分数据 # ... mysql> select count(*) from t1; +----------+ | count(*) | +----------+ | 262144 | +----------+ 1 row in set (0.10 sec) # ibdata1 增加到 76M mysql> \! ls -sihl ibdata1 923275 76M -rw-r----- 1 mysql mysql 76M 3月 18 15:34 ibdata1 # 删除这张表 mysql> drop table t1; Query OK, 0 rows affected (0.02 sec) # 空间并无释放 mysql> \! ls -sihl ibdata1 923275 76M -rw-r----- 1 mysql mysql 76M 3月 18 15:39 ibdata1
这个比较麻烦,并且严重影响服务可用性,大体几个步骤:
1.用 mysqldump 导出全部表数据;
2.关闭 MySQL 服务;
3.设置 ibdata1 为默认大小;
4.source 从新导入数据。
系统表空间在无限制增大致使磁盘满须要扩容时,没法快速的把表从系统表空间里分离出来,必须得通过停服务;改配置;扩容;从新导入数据;启服务等步骤方才可行。
对多张表的写入数据依然是顺序写,这就导致 MySQL 发布了单表空间来解决这两个问题~
单表空间不一样于系统表空间,每一个表空间和表是一一对应的关系,每张表都有本身的表空间。具体在磁盘上表现为后缀为 .ibd 的文件。
好比表 t1,对应的表空间文件为 t1.ibd
917107 96K -rw-r----- 1 mysql mysql 96K 3月 18 16:13 t1.ibd
有两种方式:
在配置文件中开启单表空间设置参数 innodb_filer_per_table,这样默认对当前库下全部表开启单表空间。
innodb_file_per_table=1
另外也能够直接建表时指定单表空间
mysql> create table t1 (id int, r1 char(36)) tablespace innodb_file_per_table; Query OK, 0 rows affected (0.04 sec)
单表空间除了解决以前说的系统表空间的几个缺点外,还有其余的优势,详细以下:
1.truncate table
操做比其余的任何表空间都快;
2.能够把不一样的表按照使用场景指定在不一样的磁盘目录;
好比日志表放在慢点的磁盘,把须要常常随机读的表放在 SSD 上等。
mysql> create table ytt_dedicated (id int) data directory = '/var/lib/mysql-files'; Query OK, 0 rows affected (0.04 sec)
optimize table
来收缩或者重建常常增删改查的表。通常过程是这样的:创建和原来表同样的表结构和数据文件,把真实数据复制到临时文件,再删掉原始表定义和数据文件,最后把临时文件的名字改成和原始表同样的。
举个例子,表 t1 以前的大小 324M
root@ytt-pc:/data/ytt/mysql/data/ytt# ls -sihl 总用量 325M 934068 4.0K -rw-r----- 1 mysql mysql 67 3月 6 23:01 db.opt 917593 12K -rw-r----- 1 mysql mysql 8.5K 3月 18 16:35 t1.frm 918181 325M -rw-r----- 1 mysql mysql 324M 3月 18 16:38 t1.ibd
进行表重建
mysql> optimize table t1; +--------+----------+----------+-------------------------------------------------------------------+ | Table | Op | Msg_type | Msg_text | +--------+----------+----------+-------------------------------------------------------------------+ | ytt.t1 | optimize | note | Table does not support optimize, doing recreate + analyze instead | | ytt.t1 | optimize | status | OK | +--------+----------+----------+-------------------------------------------------------------------+ 2 rows in set (10.26 sec)
重建期间抓取到的结果:如愿以偿看到 # 开头的临时表定义和数据文件。
root@ytt-pc:/data/ytt/mysql/data/ytt# ls -sihl 总用量 409M 934068 4.0K -rw-r----- 1 mysql mysql 67 3月 6 23:01 db.opt 917100 12K -rw-r----- 1 mysql mysql 8.5K 3月 18 16:38 '#sql-1791_7.frm' 917107 85M -rw-r----- 1 mysql mysql 84M 3月 18 16:39 '#sql-ib51-975102565.ibd' 917593 12K -rw-r----- 1 mysql mysql 8.5K 3月 18 16:35 t1.frm 918181 325M -rw-r----- 1 mysql mysql 324M 3月 18 16:38 t1.ibd
重建完成,表 t1 实际占用空间 84M
root@ytt-pc:/data/ytt/mysql/data/ytt# ls -sihl 总用量 85M 934068 4.0K -rw-r----- 1 mysql mysql 67 3月 6 23:01 db.opt 917100 12K -rw-r----- 1 mysql mysql 8.5K 3月 18 16:38 t1.frm 917107 85M -rw-r----- 1 mysql mysql 84M 3月 18 16:39 t1.ibd root@ytt-pc:/data/ytt/mysql/data/ytt#
4.能够自由移植单表
并不须要移植整个数据库,能够把单独的表在各个实例之间灵活移植。
好比如今要把 ytt.t1 的数据移植到 ytt2.t1 里。
mysql> create database ytt2; Query OK, 1 row affected (0.01 sec) mysql> use ytt2 Database changed mysql> create table t1 like ytt.t1; Query OK, 0 rows affected (0.05 sec) # 进行表数据移植。 mysql> alter table t1 discard tablespace; Query OK, 0 rows affected (0.02 sec) root@ytt-pc:/data/ytt/mysql/data/ytt# cp -rfp /tmp/t1.ibd ../ytt2/ mysql> alter table t1 import tablespace; Query OK, 0 rows affected (0.38 sec) # 确认下数据是否一致。 mysql> select (select count(*) from ytt.t1) 'ytt.t1',(select count(*) from ytt2.t1) 'ytt2.t1'; +---------+---------+ | ytt.t1 | ytt2.t1 | +---------+---------+ | 2097152 | 2097152 | +---------+---------+ 1 row in set (1.69 sec)
5.单表空间的表可使用 MySQL 的新特性;
好比表压缩,大对象更优化的磁盘存储等。
6.能够更好的管理和监控单个表的状态;
好比在 OS 层能够看到表的大小。
7.能够解除 InnoDB 系统表空间的大小限制;
InnoDB 一个表空间最大支持 64TB 数据(针对 16KB 的页大小)。若是是系统表空间,整个实例都被这个限制,单表空间则是针对单个表有 64TB 大小限制。
固然了,单表空间也并非没有缺点。好比:当多张表被大量的增删改后,表空间会有必定的膨胀;相比系统表空间,打开表须要的文件描述符增多,浪费更多的内存。
通用表空间先是出如今 MySQL Cluster 里,也就是 NDB 引擎。从 MySQL 5.7 引入到 InnoDB 引擎。通用表空间和系统表空间同样,也是共享表空间。每一个表空间能够包含一张或者多张表,也就是说通用表空间和表之间是一对多的关系。
mysql> create tablespace ts1 add datafile '/var/lib/mysql-files/ts1.ibd' engine innodb; Query OK, 0 rows affected (0.02 sec) mysql> create table t1(id int,r1 datetime) tablespace ts1; Query OK, 0 rows affected (0.02 sec) mysql> create table t2(id int,r1 datetime) tablespace ts1; Query OK, 0 rows affected (0.03 sec) mysql> create table t3(id int,r1 datetime) tablespace ts1; Query OK, 0 rows affected (0.03 sec)
通用表空间实际上是介于系统表空间和单表空间之间的一种折中的方案。
幸运的是,能够在这三个表空间里随便切换。不过要注意切换时间点,毕竟切换涉及到数据的迁移,相似 copy 文件对系统的影响。
# 表 t1 随时切换各类表空间 mysql> alter table t1 tablespace innodb_file_per_table; Query OK, 0 rows affected (14.15 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> alter table t1 tablespace innodb_system; Query OK, 0 rows affected (16.95 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> alter table t1 tablespace ts1; Query OK, 0 rows affected (13.98 sec) Records: 0 Duplicates: 0 Warnings: 0
到本篇的末尾,再来看下三种表空间如何销毁:
# 删除表空间 ts2 失败 mysql> drop tablespace ts2; ERROR 3120 (HY000): Tablespace `ts2` is not empty. mysql> show errors; +-------+------+--------------------------------+ | Level | Code | Message | +-------+------+--------------------------------+ | Error | 3120 | Tablespace `ts2` is not empty. | +-------+------+--------------------------------+ 1 row in set (0.00 sec) # 查看数据字典表来进一步查看表空间 ts2 被哪些表引用了 mysql> select regexp_replace(a.name,'/.+','') dbname,regexp_replace(a.name,'.+/','') tablename from innodb_tables a, innodb_tablespaces b where a.space = b.space and b.name= 'ts2'; +--------+-----------+ | dbname | tablename | +--------+-----------+ | ytt | t4 | +--------+-----------+ 1 row in set (0.00 sec) # 删除对应的表或者转到其余的表空间。 mysql> alter table t4 tablespace innodb_file_per_table; Query OK, 0 rows affected (0.10 sec) Records: 0 Duplicates: 0 Warnings: 0 # 删除表空间 ts2。 mysql> drop tablespace ts2; Query OK, 0 rows affected (0.02 sec)
本篇主要介绍了 MySQL 三种表空间:单表空间、系统表空间、通用表空间。并把它们的优缺点以及相关注意事项简单进行了说明,但愿你们在建表之初考虑好表空间的所属问题。