MySQL 的存储结构分为 5 级:表空间、段、簇、页、行。
- 每一个表,都对应着一个表空间
- 表中存放这一行一行的数据
- 很多行数据存放在一个数据页中
- 在表空间的磁盘文件里,会有很多很多的数据页。
- 但是一个表空间里包含的数据页太多了,不便于管理,所以在表空间又引入了一个数据区(extent)的概念
- 一个数据区对应着连续的64个数据页,每个数据页是16KB,所以一个数据区是1MB,然后256个数据区被划分为一组,这个叫做段
- 对于表空间而言,第一组数据区的第一个数据区的前3个数据页,都是固定的,里面存放了一些描述性的数据
- FSP_HDR这个数据页,里面就存放了表空间和这一组数据区的一些属性
- IBUF_BITMAP数据页,里面存放的是这一组数据页的所有insert buffer的一些信息;
- INODE数据页,里面也存放了一些特殊的信息。
- 然后这个表空间里的其他各组数据区,每一组数据区的第一个数据区的头两个数据页,都是存放特殊信息的。比如XDES数据页就是用来存放这一组数据区的一些相关属性的
- 即:
- 表空间的第一组数据区的第一个数据区的头三个数据页,都是存放特殊数据的。
- 表空间的其他数据区的第一个数据区的头两个数据页,都是存放特殊信息的。
- 对于表空间而言,第一组数据区的第一个数据区的前3个数据页,都是固定的,里面存放了一些描述性的数据
表空间
- 表空间可以看出是InnoDB存储引擎的最高层,所有的数据都存放在表空间中
- 每一个表,都对应着一个表空间,在磁盘上都会对应着一个“表名.ibd”这样的一个磁盘数据文件。即:
- 在物理层面,表空间就是对应一些磁盘上的数据文件。
- 有的表空间,比如系统表空间可能对应的是多个磁盘文件
- 分为:系统表空间、独占表空间、通用表空间、临时表空间、Undo 表空间。
段Segment:
- 表空间是由各个段组成的,常见的段有数据段、索引段、回滚段等,段是一个逻辑的概念。一个 ibd 文件(独立表空间文件)里面会由很多个段组成。
- 创建一个索引会创建两个段,一个是索引段:leaf node segment,一个是数据段:non-leaf node segment。索引段管理非叶子节点的数据。数据段管理叶子节点的数据。也就是说,一个表的段数,就是索引的个数乘以 2。
簇(区) Extent:
- 一个段Segment由很多的簇(也可以叫做区)组成,每个区的大小是MB(64个连续的页)
- 每一个段至少会有一个簇,一个段所管理的空间大小是无限的,可以一直扩展下去,但是扩展的最小单位就是簇
页(Page)
- 为了高效管理物理空间,对簇进一步细分,就得到了页。
- 簇是由连续的页(Page)组成的空间,一个簇中有64个连续的页(1MB/16KB=64)。这些页面在物理上和逻辑上都是连续的
- 跟大多数数据库一样,InnoDB也有页的概念(也可以称为块),每个页默认16KB。页是InnDB存储引擎磁盘管理的最小单位,通过innodb_page_size设置
- 一个表空间最多可以有 2 32 2^{32} 232个页,默认情况下一个页的大小为16KB,也就是一个表空间最大存储64TB的数据
注意,文件系统中也有页的概念。
操作系统和内存打交道,最小的单位是Page,文件系统的内存页通常是4KB
SHOW VARIABLES LIKE 'innodb_page_size';
假设一行数据大小是 1K,那么一个数据页可以放 16 行这样的数据。
举例:一个页放 3 行数
往表中插入数据时,如果一个页面已经写完,产生一个新的叶页面。如果一个簇的所有的页面都被用完,会从当前页面所在段新分配一个簇。
如果数据不是连续的,往已经写满的页中插入数据,会导致页面分裂:
数据库索引是存储在磁盘上的,当数据量大时,就不能把整个索引全部加载到内存了,只能逐一加载每一个磁盘页(对应索引树的节点)
行(行 Row)
InnoDB 存储引擎是面向行的(row-oriented),也就是说数据的存放按行进行存放。