mysql表空间
查看是否开启:show variables like ‘%innodb_file_per_table%’ ;
SHOW VARIABLES LIKE ‘datadir’;
0 代表系统 1代表独立
1. 独立表空间
底层的存储是怎么存储的?那么多表mysql是如何管理和维护数据和索引的?那么要搞清楚这个概念,你需要知道的是表空间的相关知识。
对于 InnoDB 存储引擎,它可以将每张表存放于独立的表空间(1->1),即 tablename.ibd
文件;也可以将数据存放于 ibdata
的共享表空间,一般命名是 ibdataX
,后面的 X 是一个具体的数字。
- 需要注意的是,**innodb_file_per_table 要在创建表之前修改,创建表之后再去修改,是不会影响已有的表结构。**
- 每张表的数据和索引都会存储在自己的表空间中。
- 可以实现单表在不同的数据库中移动(因为每张表都有独立的数据表文件)。
- 空间可以回收(通过 optimize table 等命令实现)。
2.系统表空间
默认情况下,InnoDB会在数据目录下创建一个名为 ibdata1 、大小为 12M 的文件,这个文件就是对应
的 系统表空间 在文件系统上的表示。怎么才12M?注意这个文件是 自扩展文件 ,当不够用的时候它会自己增加文件大小。
3.版本变动
在MySQL5.6.6以及之后的版本中,innodb为每一个表建立一个独立表空间 ,也就是说我们创建了多少个表,就有多少个独立表空间。使用 独立表空间 来存储表数据的话,会在该表所属数据库对应的子目录下创建一个表示该独立表空间的文件,文件名和表名相同,只不过添加了一个 .ibd 的扩展名而已。
MySQL5.7 中会在data/a的目录下生成 db.opt 文件用于保存数据库的相关配置
在8.0中 frm 和 ibd -> ibd db.opt也不再提供
扩展:
如果采取MyISAM引擎 ,data\a中会产生3个文件:
MySQL5.7 中: b.frm :描述表结构文件,字段长度等。
MySQL8.0 中 b.xxx.sdi :描述表结构文件,字段长度等
b.MYD (MYData):数据信息文件,存储数据信息(如果采用独立表存储模式)
b.MYI (MYIndex):存放索引信息文件
4.共享表空间和独立表空间的优缺点
共享表空间
Innodb的所有数据保存在一个单独的表空间里面,共享表空间可以由多个文件组成,当表使用共享表空间时,表数据可以分布在多个文件中,从而不受Innodb单表不超过64TB的限制。
默认的共享表空间的文件路径在data目录下,默认文件名为ibdata1,初始化为10M。
优点:
可以放表空间分成多个文件存放到各个磁盘上,没有单表不超过64TB的限制。
缺点:
由于多表共用一个共享表空间,当某些表进行大量删除后,共享表空间存在大量碎片,但MySQL暂未提供对共享表空间收缩的方法。
表空间中的空间只能被这个表使用
fsync操作必须在每个表上都运行一遍
mysqld必须保持一个打开的文件句柄,表太多会影响性能。(消耗很多 fd)
通过innodb_file_per_table参数将innodb表的数据和索引存放到其自己的表空间中,不再使用共享表空间,独立表空间的默认目录为innodb_data_file
独立表空间
优点:
1、 每个表有自己独立的表空间,数据和索引存放到其独立的表空间中。
2、可以轻松实现表在不同数据库之间移动
3、DROP TABLE后,表使用的空间立即被释放
4、当表中数据被大量删除后,可以使用alter table TableName engine=innodb;来进行收缩
5、表空间存在碎片时不会影响其他表的使用。
缺点:
1、使用独立表空间后,无法再将表数据分散到不同的多个文件中,如果单个存储无法提供该表所需的全部空间时,无法通过增加新存储来解决
2、innodb_file_per_table开启后,不会影响已经使用共享表空间的表。
3、单表数据较大时,导致其对于的数据文件过大而不利于维护
小结:
系统表空间
使用系统表空间的话,会在该表所在数据库对应的子目录下创建一个名为”表名.frm”的文件,表中的数据会存储在对应的文件中。
独立表空间
会在该表所在数据库对应的子目录下创建一个名为”表名.frm”和一个名为”表名.ibd”的文件,表中的数据会存储在这个ibd的文件中。8.0只有ibd 默认独立
Q:有什么用?为什么要提出namespace的概念?
对于InnoDB
存储引擎来说,每一个表空间可被划分成很多个页,表数据存放在表空间下的某些页中。表空间分为几种不同的类型。
这里谈到了区和段的概念
区
表空间中的页实在是太多了,为了更好的管理这些页面,所以提出了区(extent)的概念。对于16KB的页来说,连续的64个页就是一个区,也就是说一个区默认占用1MB的空间。无论是系统表空间还是独立表空间,都可以看作由若干个连续的区组成,每256个区被划分为一组。
其中extent0-extent255为一组,extent256-extent511为一组,依此类推,可以划分更多的组。
- FREE-空闲的区
- FREE_FRAG-有剩余空闲页面的碎片区
- FULL_FRAG-没有剩余空闲页面的碎片区
- FSEG-附属某个段的区
段
段是一些零散页的页面以及一些完整的区的集合。
为了尽量使用顺序I/O,提升磁盘的性能,作者不仅提出了区的概念,有提出了段的概念。上面说的256个区为一个组,其实这个组就是段。 每一个索引都对应2个段,一个叶子节点段,一个非叶子节点段。
组
- 每256个区分为一组
- 每个组的最开始的几个页面类型是固定的
我们每向表中插入一条记录,本质上就是向该表的聚簇索引以及所有二级索引代表的B+树的节点中插入数据。而B+树每一层中的页都会形成一个双向链表,如果以页尾单位来分配存储空间,双向链表相邻的两个页之间的物理位置可能离的非常远。前面提到使用B+树来减少存储记录的扫描行数的过程是通过一些搜索条件到B+树的叶子节点中定位到第一条符合该条件的记录,然后沿着由该记录组成的单向链表以及数据页组成的双向链表一直向后扫描就可以了。
如果双向链表中相邻的两个页的物理位置不连续,对于传统的机械硬盘来说,需要重新定位磁头位置,也就是会产生随机I/O,这样会影响磁盘的性能,所以我们应该尽量让页面链表中相邻的页的物理位置页尽量相邻,这样在扫描叶子节点中大量的记录时才可以使用顺序I/O。
所以才引入了区的概念,一个区就是在物理位置上连续的64个页。在表中的数据量很大时,为某个索引分配空间的时候就不再按照页尾单位分配了。而是按照区为单位进行分配。甚至在表中的数据非常非常多的时候,可以一次性分配多个连续的区。虽然可能造成一点点空间的浪费,但是可以消除很多随机I/O。
我们在使用B+树执行查询时,只是在扫描叶子节点的记录,如果不区分叶子节点和非叶子节点,而是统统把节点代表的页面放到申请到的区里,扫描效果就大打折扣了,所以这里对叶子节点和非叶子节点进行了区分,也就是说,叶子节点和非叶子节点都有自己独立的区。存放叶子节点的区的集合就是一个段(segment),存放非叶子节点的区的集合也是一个段。也就是说一个索引会生成两个段,一个叶子节点段,一个非叶子节点段。