InnoDB:InnoDB 磁盘结构:Tablespaces
关于
tablespace:一个数据文件,可以保存一个或多个 InnoDB 表和关联的 索引 的数据。
- 系统表空间包含 InnoDB 数据字典,在 MySQL 5.6 之前,默认情况下保存所有其他 InnoDB 表。
- 在 MySQL 5.6 和更高版本中默认启用的“innodb_file_per_table”选项允许在自己的表空间中创建表。每表一文件(File-Per-Table)表空间支持以下功能,例如有效存储页外列,表压缩和可移动表空间。
- InnoDB 引入了 MySQL 5.7.6 中的常规表空间。常规表空间是使用“CREATE TABLESPACE”语法创建的共享表空间。它们可以在 MySQL 数据目录之外创建,能够容纳多个表,并支持所有行格式的表。
MySQL NDB Cluster 还将其表分组为表空间。【???】
什么是表空间
【转自CSDN博主「IT码客」:https://blog.csdn.net/u010647035/article/details/105009979】
概述
InnoDB 表空间(Tablespace)可以看做一个逻辑概念,InnoDB 把数据保存在表空间,本质上是一个或多个磁盘文件组成的虚拟文件系统。InnoDB 表空间不仅仅存储了表和索引,它还保存了回滚日志(redo log)、插入缓冲(insert buffer)、双写缓冲(doublewrite buffer)以及其他内部数据结构。
默认情况下InnoDB存储引擎有一个共享表空间“ibdata1”,即所有数据都放在这个表空间内。如果我们配置了参数“innodb_file_per_table”,则每张表内的数据可以单独放到一个表空间内。其对应的存储文件都放在“innodb_data_home_dir”指定的目录下。
(“ibdata1”在数据库第一次有实际内容时才生成?)
- 当启用了“innodb_file_per_table”参数选项,需要注意的是,每张表的表空间内存放的只是数据、索引和插入缓冲,其它的数据,如撤销(Undo)信息、系统事务信息、二次写缓冲(double write buffer)等还是存放在原来的共享表空间内。这也就说明了另一个问题:即使在启用了参数“innodb_file_per_table”,共享表空间还是会不断地增加其大小。
InnoDB 逻辑存储结构
从 InnoDB 逻辑存储结构来看,所有的数据都被逻辑的存放在一个空间中,这个空间就叫做表空间(tablespace)。表空间由:段(segment)、区(extent)、页(page)组成。
- 段(segment)
- 段分为索引段,数据段,回滚段等。其中:
- 索引段就是非叶子结点部分,
- 而数据段就是叶子结点部分,
- 回滚段用于数据的回滚和多版本控制。
- 一个段包含256个区(256M大小)。
- 区(extent)
- 区是页的集合,一个区包含64个连续的页,默认大小为 1MB (64*16K)。
- 页(page)
- 页是 InnoDB 管理的最小单位,常见的有“FSP_HDR”,“INODE”,“INDEX”等类型。所有页的结构都是一样的,分为“文件头”(前38字节),“页数据”和“文件尾”(后8字节)。页数据根据页的类型不同而不一样。
- 每个空间都分为多个页,通常每页16 KiB。空间中的每个页面都分配有一个32位整数页码,通常称为“偏移量”(offset),它实际上只是页面与空间开头的偏移量(对于多文件空间,不一定是文件的偏移量)。因此,页面 0 位于文件偏移量 0,页面 1 位于文件偏移量 16384,依此类推。
- (InnoDB 的数据限制为64TiB,这实际上是每个空间的限制,这主要是由于页码是32位整数与默认页大小的组合: 2^32 x 16 KiB = 64 TiB )
关于“页”:
如图所示,每个page都有 38 个字节的 FIL header,以及 8 个字节的 FIL trailer(FIL 是 file 的简称)。FIL header 包含了一个表示 page type 的字段,这个字段用来确定这个 page 数据的结构。
FIL header 和 trailer 示意图如下所示:
其中:
- checksum: 4个字节32位checksum保存在header中。
- Offset: 页面初始化后,页面编号就存储在header中。根据从文件中获得的偏移量检查从该字段读取的页码是否与应该匹配的页码相符,这有助于指示读取正确,并且此字段已初始化表示页面已初始化。
- Previous/Next Page: 指向此页面类型的逻辑上一页和下一页的指针,被保存在header中。这允许建立页面的双向链接列表,并且它用于INDEX页面以及同一级别的所有页面。
- page type: 页面类型存储在标题中。为了解析其余页面数据,这是必需的。页面被分配用于文件空间管理,范围管理,事务系统,数据字典,撤消日志,blob,当然还有索引(表数据)。
- space ID: 保存在header中,space的32位整型唯一编号。
- Old-style Checksum: 旧格式32位checksum被保存在header中,不过已经被废弃,这块空间被申明为一些指针。
- LSN: 页的最后修改的64位日志序列号(LSN)存储在header中,而同一LSN的低32位存储在尾部中。
系统表空间
系统表空间是 InnoDB “数据字典”,“双写缓冲区”,“更改缓冲区”和“撤消日志”的存储区域。如果在系统表空间中创建表,而不是在“独占表空间”(File-Per-Table Tablespace)或“常规表空间”(General Tablespace)中创建表,则它也可能包含表和索引数据。
系统表空间可以具有一个或多个数据文件。默认情况下,在数据目录中创建一个名为“ibdata1”的单个系统表空间数据文件。系统表空间数据文件的大小和数量由“innodb_data_file_path”启动选项定义。
调整系统表空间的大小
增加系统表空间的大小:
- 最简单方法是将其配置为自动扩展。为此,请为“innodb_data_file_path”设置中的最后一个数据文件指定“autoextend”属性,然后重新启动服务器。
- 例如:
innodb_data_file_path=ibdata1:10M:autoextend
- 指定“autoextend”属性后,数据文件会根据需要自动以 8MB 的增量增加大小。
- “innodb_autoextend_increment”变量控制增量大小。
- 还可以通过添加另一个数据文件来增加系统表空间的大小。为此:
- 停止 MySQL 服务器。
- 如果“innodb_data_file_path”设置中的最后一个数据文件是使用“autoextend”属性定义的,请将其删除,然后修改“size”属性以反映当前数据文件的大小。要确定要指定的适当数据文件大小,请检查文件系统中的文件大小,并将该值四舍五入为最接近的 MB 值,其中 MB 等于 1024 x 1024。
- 将新的数据文件追加到“innodb_data_file_path”设置,可以选择指定“autoextend”属性。
- 只能为“innodb_data_file_path”设置中的最后一个数据文件指定“autoextend”属性。
- 启动 MySQL 服务器。
- 例如:
innodb_data_home_dir = innodb_data_file_path = /ibdata/ibdata1:10M:autoextend
- 假设数据文件随时间增长到 988MB。修改大小属性以反映当前数据文件大小之后,并指定新的 50MB 自动扩展数据文件后,这是innodb_data_file_path设置:
innodb_data_home_dir = innodb_data_file_path = /ibdata/ibdata1:988M;/disk2/ibdata2:50M:autoextend
- 添加新数据文件时,请勿指定现有文件名。 InnoDB在启动服务器时创建并初始化新的数据文件。
NOTE:
- 不能通过更改其大小属性来增加现有系统表空间数据文件的大小。例如,将 innodb_data_file_path 设置从 ibdata1:10M:autoextend 更改为 ibdata1:12M:autoextend 会在启动服务器时产生以下错误:
[ERROR] [MY-012263] [InnoDB] The Auto-extending innodb_system data file './ibdata1' is of a different size 640 pages (rounded down to MB) than specified in the .cnf file: initial 768 pages, max 0 (relevant if non-zero) pages!
- 该错误表明现有数据文件大小(以InnoDB页表示)与配置文件中指定的大小不同。如果遇到此错误,请还原以前的 innodb_data_file_path 设置,然后参考系统表空间大小调整说明。
- InnoDB 页面大小由 innodb_page_size 变量定义。默认值为 16384 字节。
减小系统表空间的大小:
- 使用 mysqldump 转储所有 InnoDB 表,包括位于 mysql 模式中的 InnoDB 表。使用以下查询在 mysql 模式中标识 InnoDB 表:
mysql> SELECT TABLE_NAME from INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='mysql' and ENGINE='InnoDB'; +---------------------------+ | TABLE_NAME | +---------------------------+ | engine_cost | | gtid_executed | | help_category | | help_keyword | | help_relation | | help_topic | | innodb_index_stats | | innodb_table_stats | | plugin | | server_cost | | servers | | slave_master_info | | slave_relay_log_info | | slave_worker_info | | time_zone | | time_zone_leap_second | | time_zone_name | | time_zone_transition | | time_zone_transition_type | +---------------------------+
- 停止服务器。
- 删除所有现有的表空间文件(*.ibd),包括“ibdata”和“ib_log”文件。【不要忘记删除 mysql 模式中的表的 *.ibd 文件】
- 删除 InnoDB 表的所有“.frm”文件。
- 为新系统表空间配置数据文件。【参见系统表空间数据文件配置】
- 重新启动服务器。
- 导入转储文件。
NOTE:
- 如果您的数据库仅使用 InnoDB 引擎,则转储所有数据库,停止服务器,删除所有数据库和InnoDB日志文件,重新启动服务器以及导入转储文件可能更简单。
为避免使用较大的系统表空间,请考虑为数据使用“独占表空间”(File-Per-Table Tablespace)。
- 【独占表空间是默认的表空间类型,在创建InnoDB表时隐式使用】。
- 与系统表空间不同,截断或删除在独占表空间中创建的 table 后,磁盘空间会返回到 os。
对系统表空间使用原始磁盘分区【???】
您可以在InnoDB system tablespace中将原始磁盘分区用作数据文件。此技术可在 Windows 以及某些 Linux 和 Unix 系统上启用无缓冲的 I/O,而不会增加文件系统的开销。在有和没有原始分区的情况下执行测试,以验证此更改是否确实提高了系统性能。
使用原始磁盘分区时,请确保运行 MySQL 服务器的用户 ID 具有该分区的读写特权。例如,如果您以mysql用户身份运行服务器,则分区必须由mysql可读和可写。如果使用“--memlock”选项运行服务器,则服务器必须以root身份运行,因此该分区必须可由root读写。
在 Linux 和 Unix 系统上分配原始磁盘分区:
- 创建新数据文件时,请在“innodb_data_file_path”选项的数据文件大小后立即指定关键字“newraw”。分区必须至少与您指定的大小一样大。
[mysqld] innodb_data_home_dir= innodb_data_file_path=/dev/hdd1:3Gnewraw;/dev/hdd2:2Gnewraw
- 重新启动服务器。 InnoDB 注意到“newraw”关键字并初始化新分区。但是,请不要创建或更改任何 InnoDB 表。否则,当您下次重新启动服务器时,InnoDB 重新初始化该分区,并且所做的更改将丢失。 (作为安全措施,InnoDB可以防止用户在指定带有“newraw”的任何分区时修改数据.)
- InnoDB 初始化新分区后,停止服务器,将数据文件规范中的“newraw”更改为“raw”:
[mysqld] innodb_data_home_dir= innodb_data_file_path=/dev/hdd1:3Graw;/dev/hdd2:2Graw
- 重新启动服务器。 InnoDB 现在允许进行更改。
在 Windows 上分配原始磁盘分区:
在 Windows 系统上,适用于 Linux 和 Unix 系统的相同步骤和随附的准则适用于 Windows,但“innodb_data_file_path”设置略有不同。
- 创建新的数据文件时,请在“innodb_data_file_path”选项的数据文件大小后立即指定关键字“newraw”:
[mysqld] innodb_data_home_dir= innodb_data_file_path=//./D::10Gnewraw
- //./对应于用于访问物理驱动器的 Windows 语法\\.\。在上面的示例中,D:是分区的驱动器号。
- 重新启动服务器。 InnoDB 注意到“newraw”关键字并初始化新分区。
- InnoDB初始化新分区后,停止服务器,将数据文件规范中的“newraw”更改为“raw”:
[mysqld] innodb_data_home_dir= innodb_data_file_path=//./D::10Graw
- 重新启动服务器。 InnoDB 现在允许进行更改。
独占(File-Per-Table)表空间
独占表空间包含单个 InnoDB 表的数据和索引,并存储在文件系统中自己的数据文件中。
独占表空间配置
InnoDB 默认情况下在独占表空间中创建表。此行为由“innodb_file_per_table”变量控制。【禁用“innodb_file_per_table”会导致 InnoDB 在系统表空间中创建表】
“innodb_file_per_table”设置可以在选项文件中指定,也可以在运行时使用“SET GLOBAL”语句进行配置(需要足够的特权来设置全局系统变量)。
- 选项文件中指定:
[mysqld] innodb_file_per_table=ON
- 在运行时使用“SET GLOBAL”:
mysql> SET GLOBAL innodb_file_per_table=ON;
独占表空间数据文件
在 MySQL 数据目录下的架构目录中的“.idb”数据文件中,创建了独占表空间。
例如,表 test.t1 的数据文件是在 MySQL 数据目录下的 test 目录中创建的:
mysql> USE test;
mysql> CREATE TABLE t1 (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100)
) ENGINE = InnoDB;
shell> cd /path/to/mysql/data/test
shell> ls
t1.ibd
- 可以使用“CREATE TABLE”语句的“DATA DIRECTORY”子句在数据目录外部隐式创建独占表空间数据文件。
独占表空间的优势
与共享表空间相比,独占表空间具有以下优点:【共享表空间:系统表空间或常规表空间】
- 截断或删除独占表空间中创建的表后,磁盘空间将返回 os。
- 截断或删除存储在共享表空间中的表会在共享表空间数据文件中创建可用空间,该可用空间仅可用于 InnoDB 数据。换句话说,在表被截断或删除后,共享表空间数据文件的大小不会缩小。
- 对驻留在共享表空间中的表进行表复制“ALTER TABLE”操作可以增加表空间占用的磁盘空间量。此类操作可能需要与表中的数据加索引一样多的额外空间。该空间不会像每个表文件表空间那样释放回 os。
- 在独占表空间中的表上执行时,“TRUNCATE TABLE”性能更好。
- 可以在单独的存储设备上创建独占表空间数据文件,以进行 I/O 优化,空间管理或备份。
- 可以从另一个 MySQL 实例导入一个位于独占表空间中的表。
- 在独占表空间中创建的表使用 Barracuda 文件格式。Barracuda 文件格式(梭鱼文件格式???)启用与“DYNAMIC”和“COMPRESSED”行格式关联的功能。
- 当发生数据损坏,备份或二进制日志不可用或无法重新启动 MySQL 服务器实例时,存储在独占表空间数据文件中的表可以节省时间并提高成功恢复的机会。
- 您可以使用 MySQL Enterprise Backup 快速备份或还原在独占表空间中创建的表,而不会中断其他 InnoDB 表的使用。这对于具有不同备份计划的表或需要较少备份的表很有用。
- 独占表空间允许通过监视表空间数据文件的大小来监视文件系统上的表大小。
- 当“innodb_flush_method”设置为“O_DIRECT”时,常见的 Linux 文件系统不允许并发写入单个文件,例如共享表空间数据文件。结果,当结合使用独占表空间和该设置时,可能会提高性能。
- 共享表空间中的表的大小受到 64TB 表空间大小限制的限制。相比之下,独占表空间都有 64TB 的大小限制,这为单个表的大小增加提供了足够的空间。
独占表空间的缺点
与共享表空间相比,独占表空间具有以下缺点:
- 使用独占表空间,每个表可能有未使用的空间,只能由同一表的行使用,如果管理不当,则会浪费空间。
- fsync 操作是针对每个表的多个文件而不是单个共享表空间的数据文件执行的。由于 fsync 操作是针对每个文件的,因此无法合并多个表的写操作,这可能导致 fsync 操作的总数更高。【???】
- mysqld 必须为独占表空间保留一个打开的文件句柄,如果独占表空间中有许多表,则这可能会影响性能。
- 每个表都有其自己的数据文件时,需要更多的文件描述符。
- 可能存在更多碎片,这可能会阻碍“DROP TABLE”和表扫描性能。但是,如果管理碎片,则独占表空间可以提高这些操作的性能。
- 删除驻留在独占表空间中的表时,将扫描缓冲池,对于大型缓冲池可能要花费几秒钟。使用广泛的内部锁定执行扫描,这可能会延迟其他操作。
- “innodb_autoextend_increment”变量定义用于在自动扩展共享表空间文件变满时扩展其大小的增量大小,该变量不适用于独占表空间文件,无论“innodb_autoextend_increment”设置如何,该文件都将自动扩展。初始的独占表空间的 extensions 很少,之后 extensions 以 4MB 为增量。
常规表空间
常规表空间是使用“CREATE TABLESPACE”语法创建的共享 InnoDB 表空间。
常规表空间功能
常规表空间功能提供以下功能:
- 类似于系统表空间,常规表空间是共享表空间,可以存储多个表的数据。
- 常规表空间比独占表空间具有潜在的内存优势。服务器在表空间的生存期内将表空间元数据保留在内存中。与独占表空间中的相同数量的表相比,较少的常规表空间中的多个表为表空间元数据消耗的内存更少。
- 常规表空间数据文件可以放置在相对于 MySQL 数据目录或独立于 MySQL 数据目录的目录中,这为您提供了独占表空间的许多数据文件和存储管理功能。与每表文件表空间一样,将数据文件放置在 MySQL 数据目录之外的功能使您可以分别管理关键表的性能,为特定表设置 RAID 或 DRBD 或将表绑定到特定磁盘。【?】
- 常规表空间支持 Antelope 和 Barracuda 文件格式【???】,因此支持所有表行格式和相关功能。支持两种文件格式,常规表空间不依赖于“innodb_file_format”或“innodb_file_per_table”设置,这些变量也不影响常规表空间。
- “TABLESPACE”选项可以与“CREATE TABLE”一起使用,以在常规表空间,独占表空间或系统表空间中创建表。
- “TABLESPACE”选项可与“ALTER TABLE”一起使用,以在常规表空间,独占表空间和系统表空间之间移动表。以前,不可能将表从每个表文件表空间移至系统表空间。使用常规表空间功能,您现在可以这样做。
创建常规表空间
常规表空间是使用“CREATE TABLESPACE”语法创建的。
CREATE TABLESPACE tablespace_name
ADD DATAFILE 'file_name'
[FILE_BLOCK_SIZE = value]
[ENGINE [=] engine_name]
- 常规表空间可以在数据目录中或在其外部创建。为避免与隐式创建的独占表空间冲突,不支持在数据目录下的子目录中创建常规表空间。
- 在数据目录之外创建常规表空间时,该目录必须在创建表空间之前存在。
- 在 MySQL 数据目录之外创建常规表空间时,会在 MySQL 数据目录中创建“.isl”文件。【?】
示例:
- 在数据目录中创建常规表空间:
mysql> CREATE TABLESPACE `ts1` ADD DATAFILE 'ts1.ibd' Engine=InnoDB;
- 在数据目录之外的目录中创建常规表空间:
mysql> CREATE TABLESPACE `ts1` ADD DATAFILE '/my/tablespace/directory/ts1.ibd' Engine=InnoDB;
- 您可以指定相对于数据目录的路径,只要表空间目录不在数据目录下即可。在此示例中,my_tablespace 目录与数据目录处于同一级别:
mysql> CREATE TABLESPACE `ts1` ADD DATAFILE '../my_tablespace/ts1.ibd' Engine=InnoDB;
- “ENGINE = InnoDB”子句必须定义为“CREATE TABLESPACE”语句的一部分,或者 InnoDB 必须定义为默认存储引擎(default_storage_engine=InnoDB)。
将表添加到常规表空间
创建 InnoDB 常规表空间后,可以使用“CREATE TABLE tbl_name ... TABLESPACE [=] tablespace_name”或“ALTER TABLE tbl_name TABLESPACE [=] tablespace_name”将表添加到表空间。
示例:
- CREATE TABLE:
mysql> CREATE TABLE t1 (c1 INT PRIMARY KEY) TABLESPACE ts1;
- ALTER TABLE:
mysql> ALTER TABLE t2 TABLESPACE ts1;
- 在 MySQL 5.7.24 中已弃用了将表分区放置在共享表空间中的支持,并且在将来的 MySQL 版本中将删除该支持。【?】
常规表空间行格式支持【????????】
使用“ALTER TABLE”在表空间之间移动表
您可以将“ALTER TABLE”与“TABLESPACE”选项一起使用,以将表移至现有的常规表空间,新的独占表空间或系统表空间。
- 要将表从独占表空间或系统表空间移至常规表空间,请指定常规表空间的名称。
- 常规表空间必须存在。
ALTER TABLE tbl_name TABLESPACE [=] tablespace_name;
- 要将表从常规表空间或独占表空间移至系统表空间,请指定“innodb_system”作为表空间名称。
ALTER TABLE tbl_name TABLESPACE [=] innodb_system;
- 要将表从系统表空间或常规表空间移至独占表空间,请指定“innodb_file_per_table”作为表空间名称。
ALTER TABLE tbl_name TABLESPACE [=] innodb_file_per_table;
NOTE:
- “ALTER TABLE ... TABLESPACE”操作始终会导致整个表的重建,即使“TABLESPACE”属性与其之前的值相比也没有变化。
- “ALTER TABLE ... TABLESPACE”语法不支持将表从临时表空间移动到持久表空间。
- “DATA DIRECTORY”子句与“CREATE TABLE ... TABLESPACE=innodb_file_per_table”一起允许,但不支持与“TABLESPACE”选项结合使用。
- 从加密表空间中移动表时有限制。
删除常规表空间
“DROP TABLESPACE”语句用于删除 InnoDB 常规表空间。
- “DROP TABLESPACE”操作之前,必须从表空间中删除所有表。如果表空间不为空,则返回错误。
使用类似于以下内容的查询来标识常规表空间中的表。
mysql> SELECT a.NAME AS space_name, b.NAME AS table_name
FROM INFORMATION_SCHEMA.INNODB_TABLESPACES a,
INFORMATION_SCHEMA.INNODB_TABLES b
WHERE a.SPACE=b.SPACE AND a.NAME LIKE 'ts1';
+------------+------------+
| space_name | table_name |
+------------+------------+
| ts1 | test/t1 |
| ts1 | test/t2 |
| ts1 | test/t3 |
+------------+------------+
NOTE:
- 如果对空的通用表空间的“DROP TABLESPACE”操作返回错误,则该表空间可能包含由服务器 Export 中断的“ALTER TABLE”操作留下的孤立临时表或中间表。
- 删除表空间中的最后一个表时,一般的 InnoDB表空间不会自动删除。必须使用“DROP TABLESPACE tablespace_name”明确删除表空间。
- 常规表空间不属于任何特定数据库。 “DROP DATABASE”操作可以删除属于常规表空间的表,但是即使“DROP DATABASE”操作删除了属于该表空间的所有表,也不能删除该表空间。必须使用“DROP TABLESPACE tablespace_name”显式删除常规表空间。
- 与系统表空间类似,截断或删除存储在通用表空间中的表会在通用表空间“.ibd”数据文件内部内部创建可用空间,该可用空间仅可用于新的 InnoDB 数据。在“DROP TABLE”操作期间删除每表文件表空间时,不会将空间释放回 os。
- “tablespace_name”是 MySQL 中区分大小写的标识符。
常规表空间限制
- 生成的表空间或现有表空间不能更改为常规表空间。
- 不支持创建临时通用表空间。
- 常规表空间不支持临时表。
- 通用表空间中存储的表只能在支持通用表空间的 MySQL 版本中打开。
- 与系统表空间类似,截断或删除存储在通用表空间中的表会在通用表空间“.ibd”数据文件内部内部创建可用空间,该可用空间仅可用于新的 InnoDB 数据。空间不会像独占表空间那样释放回 os。
- 此外,驻留在共享表空间(通用表空间或系统表空间)中的表的表复制“ALTER TABLE”操作可以增加表空间使用的空间量。此类操作需要与表中的数据以及索引一样多的额外空间。表复制“ALTER TABLE”操作所需的额外空间不会像每个表文件表空间那样释放回 os。
- 属于常规表空间的表不支持“ALTER TABLE ... DISCARD TABLESPACE”和“ALTER TABLE ...IMPORT TABLESPACE”。
- 在源和副本位于同一主机上的复制环境中,不支持“ADD DATAFILE”子句,因为这会导致源和副本在同一位置创建相同名称的表空间。【?】
- 在 MySQL 5.7.24 中已弃用了将表分区放置在常规表空间中的支持,并且在将来的 MySQL 版本中将删除该支持。【?】