InnoDB:InnoDB 磁盘结构:Tablespaces

来自Wikioe
跳到导航 跳到搜索


关于

tablespace:一个数据文件,可以保存一个或多个 InnoDB 表和关联的 索引 的数据。

  1. 系统表空间包含 InnoDB 数据字典,在 MySQL 5.6 之前,默认情况下保存所有其他 InnoDB 表。
  2. 在 MySQL 5.6 和更高版本中默认启用的“innodb_file_per_table”选项允许在自己的表空间中创建表。每表一文件(File-Per-Table)表空间支持以下功能,例如有效存储页外列,表压缩和可移动表空间。
  3. 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”指定的目录下。

InnoDB 系统表空间文件“ibdata1”.png InnoDB 独占表空间文件.png

(“ibdata1”在数据库第一次有实际内容时才生成?)

  • 当启用了“innodb_file_per_table”参数选项,需要注意的是,每张表的表空间内存放的只是数据、索引和插入缓冲,其它的数据,如撤销(Undo)信息、系统事务信息、二次写缓冲(double write buffer)等还是存放在原来的共享表空间内。这也就说明了另一个问题:即使在启用了参数“innodb_file_per_table”,共享表空间还是会不断地增加其大小。

InnoDB 逻辑存储结构

InnoDB 逻辑存储结构.png

从 InnoDB 逻辑存储结构来看,所有的数据都被逻辑的存放在一个空间中,这个空间就叫做表空间(tablespace)。表空间由:段(segment)、区(extent)、页(page)组成。

  1. (segment)
    段分为索引段数据段回滚段等。其中:
  2. 索引段就是非叶子结点部分,
  3. 而数据段就是叶子结点部分,
  4. 回滚段用于数据的回滚和多版本控制。
    一个段包含256个区(256M大小)。
  5. (extent)
    区是页的集合,一个区包含64个连续的页,默认大小为 1MB (64*16K)。
  6. (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 )


关于“页”:

InnoDB 页(page)结构.png

如图所示,每个page都有 38 个字节的 FIL header,以及 8 个字节的 FIL trailer(FIL 是 file 的简称)。FIL header 包含了一个表示 page type 的字段,这个字段用来确定这个 page 数据的结构。

FIL header 和 trailer 示意图如下所示:

InnoDB FIL header和trailer示意图.png

其中:

  • 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”启动选项定义。

调整系统表空间的大小

增加系统表空间的大小:

  1. 最简单方法是将其配置为自动扩展。为此,请为“innodb_data_file_path”设置中的最后一个数据文件指定“autoextend”属性,然后重新启动服务器。
    例如:
    innodb_data_file_path=ibdata1:10M:autoextend
    
    指定“autoextend”属性后,数据文件会根据需要自动以 8MB 的增量增加大小。
    • “innodb_autoextend_increment”变量控制增量大小。
  2. 还可以通过添加另一个数据文件来增加系统表空间的大小。为此:
    1. 停止 MySQL 服务器。
    2. 如果“innodb_data_file_path”设置中的最后一个数据文件是使用“autoextend”属性定义的,请将其删除,然后修改“size”属性以反映当前数据文件的大小。要确定要指定的适当数据文件大小,请检查文件系统中的文件大小,并将该值四舍五入为最接近的 MB 值,其中 MB 等于 1024 x 1024。
    3. 将新的数据文件追加到“innodb_data_file_path”设置,可以选择指定“autoextend”属性。
      • 只能为“innodb_data_file_path”设置中的最后一个数据文件指定“autoextend”属性。
    4. 启动 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 字节。


减小系统表空间的大小:

  1. 使用 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 |
    +---------------------------+
    
  2. 停止服务器。
  3. 删除所有现有的表空间文件(*.ibd),包括“ibdata”和“ib_log”文件。【不要忘记删除 mysql 模式中的表的 *.ibd 文件】
  4. 删除 InnoDB 表的所有“.frm”文件。
  5. 为新系统表空间配置数据文件。【参见系统表空间数据文件配置】
  6. 重新启动服务器。
  7. 导入转储文件。

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 系统上分配原始磁盘分区:

  1. 创建新数据文件时,请在“innodb_data_file_path”选项的数据文件大小后立即指定关键字“newraw”。分区必须至少与您指定的大小一样大。
    [mysqld]
    innodb_data_home_dir=
    innodb_data_file_path=/dev/hdd1:3Gnewraw;/dev/hdd2:2Gnewraw
    
  2. 重新启动服务器。 InnoDB 注意到“newraw”关键字并初始化新分区。但是,请不要创建或更改任何 InnoDB 表。否则,当您下次重新启动服务器时,InnoDB 重新初始化该分区,并且所做的更改将丢失。 (作为安全措施,InnoDB可以防止用户在指定带有“newraw”的任何分区时修改数据.)
  3. InnoDB 初始化新分区后,停止服务器,将数据文件规范中的“newraw”更改为“raw”:
    [mysqld]
    innodb_data_home_dir=
    innodb_data_file_path=/dev/hdd1:3Graw;/dev/hdd2:2Graw
    
  4. 重新启动服务器。 InnoDB 现在允许进行更改。

在 Windows 上分配原始磁盘分区:

在 Windows 系统上,适用于 Linux 和 Unix 系统的相同步骤和随附的准则适用于 Windows,但“innodb_data_file_path”设置略有不同。

  1. 创建新的数据文件时,请在“innodb_data_file_path”选项的数据文件大小后立即指定关键字“newraw”:
    [mysqld]
    innodb_data_home_dir=
    innodb_data_file_path=//./D::10Gnewraw
    
    • //./对应于用于访问物理驱动器的 Windows 语法\\.\。在上面的示例中,D:是分区的驱动器号。
  2. 重新启动服务器。 InnoDB 注意到“newraw”关键字并初始化新分区。
  3. InnoDB初始化新分区后,停止服务器,将数据文件规范中的“newraw”更改为“raw”:
    [mysqld]
    innodb_data_home_dir=
    innodb_data_file_path=//./D::10Graw
    
  4. 重新启动服务器。 InnoDB 现在允许进行更改。

独占(File-Per-Table)表空间

独占表空间包含单个 InnoDB 表的数据和索引,并存储在文件系统中自己的数据文件中。

独占表空间配置

InnoDB 默认情况下在独占表空间中创建表。此行为由“innodb_file_per_table”变量控制。【禁用“innodb_file_per_table”会导致 InnoDB 在系统表空间中创建表】


“innodb_file_per_table”设置可以在选项文件中指定,也可以在运行时使用“SET GLOBAL”语句进行配置(需要足够的特权来设置全局系统变量)。

  1. 选项文件中指定:
    [mysqld]
    innodb_file_per_table=ON
    
  2. 在运行时使用“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”子句在数据目录外部隐式创建独占表空间数据文件。

独占表空间的优势

与共享表空间相比,独占表空间具有以下优点:【共享表空间:系统表空间或常规表空间】

  1. 截断或删除独占表空间中创建的表后,磁盘空间将返回 os
    截断或删除存储在共享表空间中的表会在共享表空间数据文件中创建可用空间,该可用空间仅可用于 InnoDB 数据。换句话说,在表被截断或删除后,共享表空间数据文件的大小不会缩小
  2. 对驻留在共享表空间中的表进行表复制“ALTER TABLE”操作可以增加表空间占用的磁盘空间量。此类操作可能需要与表中的数据加索引一样多的额外空间。该空间不会像每个表文件表空间那样释放回 os。
  3. 在独占表空间中的表上执行时,“TRUNCATE TABLE”性能更好
  4. 可以在单独的存储设备上创建独占表空间数据文件,以进行 I/O 优化,空间管理或备份。
  5. 可以从另一个 MySQL 实例导入一个位于独占表空间中的表
  6. 在独占表空间中创建的表使用 Barracuda 文件格式。Barracuda 文件格式(梭鱼文件格式???)启用与“DYNAMIC”和“COMPRESSED”行格式关联的功能。
  7. 当发生数据损坏,备份或二进制日志不可用或无法重新启动 MySQL 服务器实例时,存储在独占表空间数据文件中的表可以节省时间并提高成功恢复的机会
  8. 您可以使用 MySQL Enterprise Backup 快速备份或还原在独占表空间中创建的表,而不会中断其他 InnoDB 表的使用。这对于具有不同备份计划的表或需要较少备份的表很有用。
  9. 独占表空间允许通过监视表空间数据文件的大小来监视文件系统上的表大小。
  10. 当“innodb_flush_method”设置为“O_DIRECT”时,常见的 Linux 文件系统不允许并发写入单个文件,例如共享表空间数据文件。结果,当结合使用独占表空间和该设置时,可能会提高性能。
  11. 共享表空间中的表的大小受到 64TB 表空间大小限制的限制。相比之下,独占表空间都有 64TB 的大小限制,这为单个表的大小增加提供了足够的空间。

独占表空间的缺点

与共享表空间相比,独占表空间具有以下缺点:

  1. 使用独占表空间,每个表可能有未使用的空间,只能由同一表的行使用,如果管理不当,则会浪费空间。
  2. fsync 操作是针对每个表的多个文件而不是单个共享表空间的数据文件执行的。由于 fsync 操作是针对每个文件的,因此无法合并多个表的写操作,这可能导致 fsync 操作的总数更高。【???】
  3. mysqld 必须为独占表空间保留一个打开的文件句柄,如果独占表空间中有许多表,则这可能会影响性能。
  4. 每个表都有其自己的数据文件时,需要更多的文件描述符。
  5. 可能存在更多碎片,这可能会阻碍“DROP TABLE”和表扫描性能。但是,如果管理碎片,则独占表空间可以提高这些操作的性能。
  6. 删除驻留在独占表空间中的表时,将扫描缓冲池,对于大型缓冲池可能要花费几秒钟。使用广泛的内部锁定执行扫描,这可能会延迟其他操作。
  7. “innodb_autoextend_increment”变量定义用于在自动扩展共享表空间文件变满时扩展其大小的增量大小,该变量不适用于独占表空间文件,无论“innodb_autoextend_increment”设置如何,该文件都将自动扩展。初始的独占表空间的 extensions 很少,之后 extensions 以 4MB 为增量。

常规表空间

撤消(Undo)表空间

临时表空间