多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
### 表在文件系统中的表示 每个表的信息其实可以分为两种: 1. 表结构的定义 2. 表中的数据 `表结构`就是该表的名称是啥,表里边有多少列,每个列的数据类型是啥,有啥约束条件和索引,用的是啥字符集和比较规则吧啦吧啦的各种信息,这些信息都体现在了我们的建表语句中了。为了保存这些信息,`InnoDB`和`MyISAM`这两种存储引擎都在`数据目录`下对应的数据库子目录下创建了一个专门用于描述表结构的文件,文件名是这样: ~~~ 表名.frm ~~~ #### InnoDB是如何存储表数据的 ##### 系统表空间(system tablespace) 这个所谓的`系统表空间`可以对应文件系统上一个或多个实际的文件,默认情况下,`InnoDB`会在`数据目录`下创建一个名为`ibdata1` 在一个MySQL服务器中,系统表空间只有一份。从MySQL5.5.7到MySQL5.6.6之间的各个版本中,我们表中的数据都会被默认存储到这个***系统表空间***。 ##### 独立表空间(file-per-table tablespace) 在MySQL5.6.6以及之后的版本中,`InnoDB`并不会默认的把各个表的数据存储到系统表空间中,而是为每一个表建立一个独立表空间,也就是说我们创建了多少个表,就有多少个独立表空间。使用`独立表空间`来存储表数据的话,会在该表所属数据库对应的子目录下创建一个表示该`独立表空间`的文件,文件名和表名相同,只不过添加了一个`.ibd`的扩展名而已,所以完整的文件名称长这样: ~~~ 表名.ibd ~~~ 比方说假如我们使用了`独立表空间`去存储`xiaohaizi`数据库下的`test`表的话,那么在该表所在数据库对应的`xiaohaizi`目录下会为`test`表创建这两个文件: ~~~ test.frm test.ibd ~~~ ##### 其他类型的表空间 随着MySQL的发展,除了上述两种老牌表空间之外,现在还新提出了一些不同类型的表空间,比如通用表空间(general tablespace)、undo表空间(undo tablespace)、临时表空间(temporary tablespace)吧啦吧啦的,具体情况我们就不细唠叨了,等用到的时候再提。 ## 文件系统对数据库的影响 因为`MySQL`的数据都是存在文件系统中的,就不得不受到文件系统的一些制约,这在数据库和表的命名、表的大小和性能方面体现的比较明显,比如下边这些方面: * 数据库名称和表名称不得超过文件系统所允许的最大长度。 每个数据库都对应`数据目录`的一个子目录,数据库名称就是这个子目录的名称;每个表都会在数据库子目录下产生一个和表名同名的`.frm`文件,如果是`InnoDB`的独立表空间或者使用`MyISAM`引擎还会有别的文件的名称与表名一致。这些目录或文件名的长度都受限于文件系统所允许的长度~ * 特殊字符的问题 为了避免因为数据库名和表名出现某些特殊字符而造成文件系统不支持的情况,`MySQL`会把数据库名和表名中所有除数字和拉丁字母以外的所有字符在文件名里都映射成`@+编码值`的形式作为文件名。比方说我们创建的表的名称为`'test?'`,由于`?`不属于数字或者拉丁字母,所以会被映射成编码值,所以这个表对应的`.frm`文件的名称就变成了`test@003f.frm`。 * 文件长度受文件系统最大长度限制 对于`InnoDB`的独立表空间来说,每个表的数据都会被存储到一个与表名同名的`.ibd`文件中;对于`MyISAM`存储引擎来说,数据和索引会分别存放到与表同名的`.MYD`和`.MYI`文件中。这些文件会随着表中记录的增加而增大,它们的大小受限于文件系统支持的最大文件大小。 ## MySQL系统数据库简介 我们前边提到了MySQL的几个系统数据库,这几个数据库包含了MySQL服务器运行过程中所需的一些信息以及一些运行状态信息,我们现在稍微了解一下。 * `mysql` 这个数据库贼核心,它存储了MySQL的用户账户和权限信息,一些存储过程、事件的定义信息,一些运行过程中产生的日志信息,一些帮助信息以及时区信息等。 * `information_schema` 这个数据库保存着MySQL服务器维护的所有其他数据库的信息,比如有哪些表、哪些视图、哪些触发器、哪些列、哪些索引吧啦吧啦。这些信息并不是真实的用户数据,而是一些描述性信息,有时候也称之为元数据。 * `performance_schema` 这个数据库里主要保存MySQL服务器运行过程中的一些状态信息,算是对MySQL服务器的一个性能监控。包括统计最近执行了哪些语句,在执行过程的每个阶段都花费了多长时间,内存的使用情况等等信息。 * `sys` 这个数据库主要是通过视图的形式把`information_schema`和`performance_schema`结合起来,让程序员可以更方便的了解MySQL服务器的一些性能信息。 ### 区(extent)的概念 表空间中的页实在是太多了,为了更好的管理这些页面,设计`InnoDB`的大叔们提出了`区`(英文名:`extent`)的概念。对于16KB的页来说,连续的64个页就是一个`区`,也就是说一个区默认占用1MB空间大小。不论是系统表空间还是独立表空间,都可以看成是由若干个区组成的,每256个区被划分成一组。画个图表示就是这样: ![](https://img.kancloud.cn/d3/42/d3422f83c59a4a9f2ebd94eb8fb940ac_662x547.png) **表空间被划分为许多连续的`区`,每个区默认由64个页组成,每256个区划分为一组,每个组的最开始的几个页面类型是固定的** ### 段(segment)的概念 叶子节点有自己独有的`区`,非叶子节点也有自己独有的`区`。存放叶子节点的区的集合就算是一个`段`(`segment`),存放非叶子节点的区的集合也算是一个`段`。也就是说一个索引会生成2个段,一个叶子节点段,一个非叶子节点段。 为了考虑以完整的区为单位分配给某个段对于数据量较小的表太浪费存储空间的这种情况,`InnoDB`提出了一个碎片(fragment)区的概念,也就是在一个碎片区中,并不是所有的页都是为了存储同一个段的数据而存在的,而是碎片区中的页可以用于不同的目的,比如有些页用于段A,有些页用于段B,有些页甚至哪个段都不属于。碎片区直属于表空间,并不属于任何一个段。所以此后为某个段分配存储空间的策略是这样的: * 在刚开始向表中插入数据的时候,段是从某个碎片区以单个页面为单位来分配存储空间的。 * 当某个段已经占用了32个碎片区页面之后,就会以完整的区为单位来分配存储空间。 ### 区的分类 * 空闲的区:现在还没有用到这个区中的任何页面。 * 有剩余空间的碎片区:表示碎片区中还有可用的页面。 * 没有剩余空间的碎片区:表示碎片区中的所有页面都被使用,没有空闲页面。 * 附属于某个段的区。每一个索引都可以分为叶子节点段和非叶子节点段,除此之外InnoDB还会另外定义一些特殊作用的段,在这些段中的数据量很大时将使用区来作为基本的分配单位。 这4种类型的区也可以被称为区的4种状态(`State`) | 状态名 | 含义 | | :-: | :-: | | `FREE` | 空闲的区 | | `FREE_FRAG` | 有剩余空间的碎片区 | | `FULL_FRAG` | 没有剩余空间的碎片区 | | `FSEG` | 附属于某个段的区 | 处于`FREE`、`FREE_FRAG`以及`FULL_FRAG`这三种状态的区都是独立的,算是直属于表空间;而处于`FSEG`状态的区是附属于某个段的。