第15章InnoDB存储引擎

目录

15.1 InnoDB简介
15.1.1使用InnoDB表的好处
15.1.2 InnoDB表的最佳实践
15.1.3验证InnoDB是默认存储引擎
15.1.4使用InnoDB进行测试和基准测试
15.2 InnoDB和ACID模型
15.3 InnoDB多版本控制
15.4 InnoDB架构
15.5 InnoDB内存中结构
15.5.1缓冲池
15.5.2更改缓冲区
15.5.3自适应哈希索引
15。5。4日志缓冲区
15.6 InnoDB磁盘结构
15.6.1表格
15.6.2索引
15.6.3表空间
15.6.4 Doublewrite Buffer
15.6.5重做日志
15.6.6撤消日志
15.7 InnoDB锁定和交易模型
15.7.1 InnoDB锁定
15.7.2 InnoDB事务模型
15.7.3 InnoDB中不同SQL语句设置的锁
15.7.4幻像行
15.7.5 InnoDB中的死锁
15.8 InnoDB配置
15.8.1 InnoDB启动配置
15.8.2配置InnoDB进行只读操作
15.8.3 InnoDB缓冲池配置
15.8.4配置InnoDB的线程并发
15.8.5配置后台InnoDB I / O线程数
15.8.6在Linux上使用异步I / O.
15.8.7配置InnoDB主线程I / O速率
15.8.8配置自旋锁轮询
15.8.9配置InnoDB清除调度
15.8.10配置InnoDB的优化器统计信息
15.8.11配置索引页面的合并阈值
15.8.12启用专用MySQL服务器的自动配置
15.9 InnoDB表和页面压缩
15.9.1 InnoDB表压缩
15.9.2 InnoDB页面压缩
15.10 InnoDB行格式
15.11 InnoDB磁盘I / O和文件空间管理
15.11.1 InnoDB磁盘I / O.
15.11.2文件空间管理
15.11.3 InnoDB检查点
15.11.4对表进行碎片整理
15.11.5使用TRUNCATE TABLE回收磁盘空间
15.12 InnoDB和在线DDL
15.12.1在线DDL操作
15.12.2在线DDL性能和并发
15.12.3在线DDL空间要求
15.12.4使用在线DDL简化DDL语句
15.12.5在线DDL失败条件
15.12.6在线DDL限制
15.13 InnoDB启动选项和系统变量
15.14 InnoDB INFORMATION_SCHEMA表
15.14.1 InnoDB INFORMATION_SCHEMA关于压缩的表
15.14.2 InnoDB INFORMATION_SCHEMA交易和锁定信息
15.14.3 InnoDB INFORMATION_SCHEMA模式对象表
15.14.4 InnoDB INFORMATION_SCHEMA FULLTEXT索引表
15.14.5 InnoDB INFORMATION_SCHEMA缓冲池表
15.14.6 InnoDB INFORMATION_SCHEMA度量表
15.14.7 InnoDB INFORMATION_SCHEMA临时表信息表
15.14.8从INFORMATION_SCHEMA.FILES检索InnoDB表空间元数据
15.15 InnoDB与MySQL性能模式的集成
15.15.1使用性能模式监控InnoDB表的ALTER TABLE进度
15.15.2使用性能模式监控InnoDB Mutex等待
15.16 InnoDB监视器
15.16.1 InnoDB监控类型
15.16.2启用InnoDB监视器
15.16.3 InnoDB标准监视器和锁定监视器输出
15.17 InnoDB备份和恢复
15.17.1 InnoDB备份
15.17.2 InnoDB恢复
15.18 InnoDB和MySQL复制
15.19 InnoDB memcached插件
15.19.1 InnoDB memcached插件的好处
15.19.2 InnoDB memcached架构
15.19.3设置InnoDB memcached插件
15.19.4 InnoDB memcached多个get和Range Query支持
15.19.5 InnoDB memcached插件的安全注意事项
15.19.6为InnoDB memcached插件编写应用程序
15.19.7 InnoDB memcached插件和复制
15.19.8 InnoDB memcached插件内部
15.19.9对InnoDB memcached插件进行故障诊断
15.20 InnoDB故障排除
15.20.1对InnoDB I / O问题进行故障排除
15.20.2强制InnoDB恢复
15.20.3 InnoDB数据字典操作故障排除
15.20.4 InnoDB错误处理

15.1 InnoDB简介

InnoDB 是一种平衡高可靠性和高性能的通用存储引擎。 在MySQL 8.0中, InnoDB 是默认的MySQL存储引擎。 除非您配置了不同的默认存​​储引擎,否则发出 CREATE TABLE 不带 ENGINE= 子句的语句会创建 InnoDB 表。

InnoDB的主要优势

表15.1 InnoDB存储引擎功能

特征 支持
B树索引
备份/时间点恢复 (在服务器中实现,而不是在存储引擎中实现。)
群集数据库支持 没有
聚集索引
压缩数据
数据缓存
加密数据 是(通过加密功能在服务器中实现;在MySQL 5.7及更高版本中,支持静态数据表空间加密。)
外键支持
全文搜索索引 是(在MySQL 5.6及更高版本中可以使用InnoDB对FULLTEXT索引的支持。)
地理空间数据类型支持
地理空间索引支持 是(在MySQL 5.7及更高版本中可以使用InnoDB对地理空间索引的支持。)
哈希索引 否(InnoDB在内部利用哈希索引来实现其自适应哈希索引功能。)
索引缓存
锁定粒度
MVCC
复制支持 (在服务器中实现,而不是在存储引擎中实现。)
存储限制 64TB
T树索引 没有
交易
更新数据字典的统计信息

要比较 InnoDB MySQL提供的其他存储引擎 的功能 ,请参阅 第16章 备用存储引擎中 存储引擎功能

InnoDB增强功能和新功能

有关 InnoDB 增强功能和新功能的信息,请参阅:

额外的InnoDB信息和资源

15.1.1使用InnoDB表的好处

您可能会发现有 InnoDB 利于以下原因的表:

  • 如果您的服务器因硬件或软件问题而崩溃,无论当时数据库中发生了什么,您都无需在重新启动数据库后执行任何特殊操作。 InnoDB 崩溃恢复会 自动完成在崩溃之前提交的所有更改,并撤消正在进行但未提交的任何更改。 只需重新启动并继续您离开的地方。

  • InnoDB 存储引擎维护它自己的 缓冲池 ,当数据被访问主内存中缓存表和索引数据。 经常使用的数据直接从内存中处理。 此缓存适用于许多类型的信息并加快处理速度。 在专用数据库服务器上,通常会将最多80%的物理内存分配给缓冲池。

  • 如果将相关数据拆分到不同的表中,则可以设置 强制 引用完整性的 外键 更新或删除数据,并自动更新或删除其他表中的相关数据。 尝试将数据插入到辅助表中,而不在主表中显示相应的数据,并且坏数据会自动被踢出。

  • 如果数据在磁盘或内存中损坏, 校验和 机制会在您使用之前提醒您伪造数据。

  • 使用 每个表的 相应 主键 设计数据库时 ,将自动优化涉及这些列的操作。 引用 WHERE 子句, ORDER BY 子句, GROUP BY 子句和 连接 操作中 的主键列非常快

  • 插入,更新和删除通过称为 更改缓冲 的自动机制进行优化 InnoDB 不仅允许对同一个表进行并发读写访问,还可以缓存已更改的数据以简化磁盘I / O.

  • 性能优势不仅限于具有长时间运行查询的巨型表。 当从表中反复访问相同的行时,称为 自适应哈希索引的功能 会接管以使这些查找更快,就像它们来自哈希表一样。

  • 您可以压缩表和关联的索引。

  • 您可以创建和删除索引,而对性能和可用性的影响要小得多。

  • 截断 每个表 文件表 空间非常快,并且可以释放磁盘空间以供操作系统重用,而不是释放 系统表空间 中只能 InnoDB 重用的 空间

  • BLOB 使用 DYNAMIC 行格式 ,表数据的存储布局对于 长文本字段 更有效

  • 您可以通过查询 INFORMATION_SCHEMA 来监视存储引擎的内部工作方式

  • 您可以通过查询 性能架构 来监控存储引擎的性能详细信息

  • 您可以自由地将 InnoDB 表与来自其他MySQL存储引擎的表 混合 ,甚至可以在同一语句中。 例如,您可以使用 连接 操作来组合 单个查询中的 数据 InnoDB MEMORY 表。

  • InnoDB 专为处理大量数据时的CPU效率和最高性能而设计。

  • InnoDB 表可以处理大量数据,即使在文件大小限制为2GB的操作系统上也是如此。

对于 InnoDB 您可以在应用程序代码中应用特异性调节技术,请参阅 第8.5节,“优化InnoDB表”

15.1.2 InnoDB表的最佳实践

本节介绍使用 InnoDB 时的最佳实践

  • 使用最常查询的列或列 指定 每个表 主键 如果没有明显的主键 ,则指定 自动增量 值。

  • 根据来自这些表的相同ID值从多个表中提取数据的位置 使用 连接 要获得快速连接性能,请 在连接列上 定义 外键 ,并在每个表中声明具有相同数据类型的列。 添加外键可确保对引用的列建立索引,从而提高性能。 外键还会将删除或更新传播到所有受影响的表,如果父表中不存在相应的ID,则会阻止在子表中插入数据。

  • 关闭 自动提交 每秒承诺数百次会限制性能(受存储设备写入速度的限制)。

  • 分组组相关的 DML 操作成 交易 ,通过包围他们 START TRANSACTION COMMIT 报表。 虽然你不想过于频繁地提交,你也不想发出的巨大的批次 INSERT UPDATE 或者 DELETE ,如果没有犯了几个小时运行的语句。

  • 不使用 LOCK TABLES 语句。 InnoDB 可以同时处理多个会话,同时读取和写入同一个表,而不会牺牲可靠性或高性能。 要获得对一组行的独占写访问权,请使用 SELECT ... FOR UPDATE 语法仅锁定要更新的行。

  • 启用该 innodb_file_per_table 选项或使用通用表空间将表的数据和索引放入单独的文件中,而不是 系统表空间

    innodb_file_per_table 默认情况下启用 选项。

  • 评估您的数据和访问模式是否受益于 InnoDB 表或页面 压缩 功能。 您可以在 InnoDB 不牺牲读/写功能的情况下 压缩 表。

  • 使用选项运行服务器, --sql_mode=NO_ENGINE_SUBSTITUTION 以防止在使用 ENGINE= 子句中 指定的引擎出现问题时使用其他存储引擎创建表 CREATE TABLE

15.1.3验证InnoDB是默认存储引擎

发出 SHOW ENGINES 语句以查看可用的MySQL存储引擎。 寻找 DEFAULT InnoDB 行。

mysql> SHOW ENGINES;

或者,查询 INFORMATION_SCHEMA.ENGINES 表。

mysql> SELECT * FROM INFORMATION_SCHEMA.ENGINES;

15.1.4使用InnoDB进行测试和基准测试

如果 InnoDB 不是您的默认存储引擎,则可以 InnoDB 通过 --default-storage-engine=InnoDB 在命令行中定义 的服务器重新启动服务器 default-storage-engine=innodb [mysqld] MySQL服务器选项文件 部分中 定义 来确定数据库服务器或应用程序是否正常工作

由于更改默认存储引擎仅会在创建新表时影响新表,因此请运行所有应用程序安装和设置步骤,以确认所有内容都已正确安装。 然后练习所有应用程序功能,以确保所有数据加载,编辑和查询功能都能正常工作。 如果表依赖于特定于另一个存储引擎的功能,您将收到错误; 将该 子句 添加 语句中以避免错误。 ENGINE=other_engine_name CREATE TABLE

如果您没有对存储引擎做出深思熟虑的决定,并且想要预览某些表在使用时创建的工作方式 InnoDB ,请 ALTER TABLE table_name ENGINE=InnoDB; 为每个表 发出命令 或者,要在不打扰原始表的情况下运行测试查询和其他语句,请复制:

CREATE TABLE InnoDB_Table(...)ENGINE = InnoDB AS SELECT * FROM other_engine_table;

要在实际工作负载下评估完整应用程序的性能,请安装最新的MySQL服务器并运行基准测试。

测试整个应用程序生命周期,从安装,大量使用和服务器重启。 在数据库忙于模拟电源故障时终止服务器进程,并在重新启动服务器时验证数据是否已成功恢复。

测试任何复制配置,尤其是在主服务器和从服务器上使用不同的MySQL版本和选项时。

15.2 InnoDB和ACID模型

ACID 模式是一组数据库设计原则强调的是,对于业务数据和关键任务应用重要的可靠性方面。 MySQL包含诸如的组件 InnoDB 存储引擎与ACID模型紧密结合,因此数据不会损坏,并且不会因软件崩溃和硬件故障等特殊情况而导致结果失真。 当您依赖符合ACID的功能时,您无需重新发明一致性检查和崩溃恢复机制。 如果您有其他软件安全措施,超可靠硬件或可以容忍少量数据丢失或不一致的应用程序,您可以调整MySQL设置以交换一些ACID可靠性以获得更高的性能或吞吐量。

以下部分讨论MySQL功能(尤其是 InnoDB 存储引擎) 如何 与ACID模型的类别进行交互:

  • :原子性。

  • C :一致性。

  • ::隔离。

  • D :耐用性。

原子性

ACID模型 原子性 方面主要涉及 InnoDB 交易 相关的MySQL功能包括:

  • 自动提交设置。

  • COMMIT 声明。

  • ROLLBACK 声明。

  • 来自 INFORMATION_SCHEMA 表格的 运营数据

一致性

ACID模型 一致性 方面主要涉及内部 InnoDB 处理以保护数据免于崩溃。 相关的MySQL功能包括:

隔离

ACID模型 隔离 方面主要涉及 InnoDB 事务 ,特别 是适用于每个事务 隔离级别 相关的MySQL功能包括:

  • 自动提交 设置。

  • SET ISOLATION LEVEL 声明。

  • InnoDB 锁定 的低级细节 在性能调整期间,您可以通过 INFORMATION_SCHEMA 表格 查看这些详细信

耐久力

ACID模型 持久性 方面涉及MySQL软件功能与您的特定硬件配置交互。 由于取决于CPU,网络和存储设备的功能的许多可能性,这方面是最复杂的提供具体指导方针。 (这些指南可能采取购买 新硬件 的形式 。)相关的MySQL功能包括:

  • InnoDB doublewrite buffer ,由 innodb_doublewrite 配置选项 打开和关闭

  • 配置选项 innodb_flush_log_at_trx_commit

  • 配置选项 sync_binlog

  • 配置选项 innodb_file_per_table

  • 在存储设备中写入缓冲区,例如磁盘驱动器,SSD或RAID阵列。

  • 存储设备中的电池备份缓存。

  • 用于运行MySQL的操作系统,特别是它对 fsync() 系统调用的 支持

  • 不间断电源(UPS)保护运行MySQL服务器和存储MySQL数据的所有计算机服务器和存储设备的电源。

  • 您的备份策略,例如备份的频率和类型以及备份保留期。

  • 对于分布式或托管数据应用程序,MySQL服务器的硬件所在的数据中心的特定特征,以及数据中心之间的网络连接。

15.3 InnoDB多版本控制

InnoDB 是一个 多版本的存储引擎 :它保存有关已更改行的旧版本的信息,以支持并发和 回滚 等事务功能 此信息存储在表空间中称为 回滚段 的数据结构中(在Oracle中的类似数据结构之后)。 InnoDB 使用回滚段中的信息来执行事务回滚中所需的撤消操作。 它还使用该信息构建行的早期版本以进行 一致读取

在内部, InnoDB 为数据库中存储的每一行添加三个字段。 6字节 DB_TRX_ID 字段指示插入或更新行的最后一个事务的事务标识符。 此外,删除在内部被视为更新,其中行中的特殊位被设置为将其标记为已删除。 每行还包含一个 DB_ROLL_PTR 称为滚动指针 的7字节 字段。 roll指针指向写入回滚段的撤消日志记录。 如果更新了行,则撤消日志记录包含在更新行之前重建行内容所需的信息。 一个6字节的 DB_ROW_ID 字段包含一个行ID,当插入新行时,该行ID会单调增加。 如果 InnoDB 自动生成聚簇索引,索引包含行ID值。 否则,该 DB_ROW_ID 列不会出现在任何索引中。

撤消段中的撤消日志分为插入和更新撤消日志。 只在事务回滚中才需要插入撤消日志,并且可以在事务提交后立即丢弃。 更新撤消日志也用于一致性读取,但只有在没有事务 InnoDB 已分配快照的情况下 才能丢弃它们 ,在一致读取中可能需要更新撤消日志中的信息来构建数据库的早期版本行。

定期提交您的交易,包括那些只发出一致读取的交易。 否则, InnoDB 无法从更新撤消日志中丢弃数据,并且回滚段可能会变得太大,从而填满了表空间。

回滚段中撤消日志记录的物理大小通常小于相应的插入或更新行。 您可以使用此信息计算回滚段所需的空间。

InnoDB 多版本控制方案中,使用SQL语句删除行时,不会立即从数据库中物理删除该行。 InnoDB 只有在丢弃为删除写入的更新撤消日志记录时,才会物理删除相应的行及其索引记录。 此删除操作称为 清除 ,并且速度非常快,通常与执行删除的SQL语句的时间顺序相同。

如果你在表中以大约相同的速率插入和删除少量批次的行,则清除线程可能开始落后,并且由于所有 行, 表可以变得越来越大 ,使得所有磁盘都受到限制慢。 在这种情况下,通过调整 innodb_max_purge_lag 系统变量 来限制新行操作,并将更多资源分配给清除线程 有关 更多信息 请参见 第15.13节“InnoDB启动选项和系统变量”

多版本控制和二级索引

InnoDB 多版本并发控制(MVCC)以不同于聚簇索引的方式处理二级索引。 聚集索引中的记录就地更新,其隐藏的系统列指向可以重建早期版本记录的撤消日志条目。 与聚簇索引记录不同,二级索引记录不包含隐藏的系统列,也不会就地更新。

更新二级索引列时,旧的二级索引记录将被删除标记,插入新记录,最终清除删除标记的记录。 当二级索引记录被删除标记或二级索引页面由较新的事务更新时, InnoDB 查找聚簇索引中的数据库记录。 在聚簇索引中,将 DB_TRX_ID 检查记录,如果在启动读取事务后修改了记录,则会从撤消日志中检索正确的记录版本。

如果二级索引记录被标记为删除或二级索引页面由较新的事务更新, 则不使用 覆盖索引 技术。 而不是从索引结构返回值,而是 InnoDB 在聚簇索引中查找记录。

但是,如果 启用 索引条件下推(ICP) 优化,并且 WHERE 只能使用索引中的字段来评估条件的 某些部分 ,则MySQL服务器仍会将此部分 WHERE 条件下推到存储引擎,在此处使用指数。 如果未找到匹配的记录,则避免聚集索引查找。 如果找到匹配的记录,即使在删除标记的记录中,也会 InnoDB 查找聚簇索引中的记录。

15.4 InnoDB架构

下图显示了构成 InnoDB 存储引擎体系 结构的内存和磁盘结构 有关每种结构的信息,请参见 第15.5节“InnoDB内存中结构” 第15.6节“InnoDB On-Disk Structures”

图15.1 InnoDB架构

InnoDB architecture diagram showing in-memory and on-disk structures.

15.5 InnoDB内存中结构

本节介绍 InnoDB 内存中的结构和相关主题。

15.5.1缓冲池

缓冲池是主存储器中的一个区域,用于在访问时缓存表和索引数据。 缓冲池允许直接从内存处理常用数据,从而加快处理速度。 在专用服务器上,通常会将最多80%的物理内存分配给缓冲池。

为了提高大容量读取操作的效率,缓冲池被分成 可以容纳多行的 页面 为了提高缓存管理的效率,缓冲池被实现为链接的页面列表; 使用 LRU 算法 的变体,很少使用的数据在缓存中老化

了解如何利用缓冲池将频繁访问的数据保存在内存中是MySQL调优的一个重要方面。

缓冲池LRU算法

使用最近最少使用(LRU)算法的变体将缓冲池作为列表进行管理。 当需要空间将新页面添加到缓冲池时,最近最少使用的页面被逐出,并且新页面被添加到列表的中间。 此中点插入策略将列表视为两个子列表:

  • 在头部, 最近访问过 的新( 年轻 )页面 的子列表

  • 在尾部,是最近访问的旧页面的子列表

图15.2缓冲池列表

Content is described in the surrounding text.

该算法保留新子列表中查询大量使用的页面。 旧子列表包含较少使用的页面; 这些页面是 驱逐的 候选人

默认情况下,算法操作如下:

  • 3/8的缓冲池专用于旧子列表。

  • 列表的中点是新子列表的尾部与旧子列表的头部相交的边界。

  • InnoDB 将页面读入缓冲池时,它最初将其插入中点(旧子列表的头部)。 可以读取页面,因为它是用户指定的操作(如SQL查询)所必需的,或者是 由自动执行的 预读 操作的 一部分 InnoDB

  • 访问旧子列表中的页面使其 年轻 ,将其移动到缓冲池的头部(新子列表的头部)。 如果因为需要而读取页面,则会立即进行第一次访问,并使页面变得年轻。 如果由于预读而读取了页面,则第一次访问不会立即发生(并且在页面被逐出之前可能根本不会发生)。

  • 随着数据库的运行,在缓冲池的页面没有被访问的 年龄 通过向列表的尾部移动。 新旧子列表中的页面随着其他页面的变化而变旧。 旧子列表中的页面也会随着页面插入中点而老化。 最终,仍然未使用的页面到达旧子列表的尾部并被逐出。

默认情况下,查询读取的页面会立即移动到新的子列表中,这意味着它们会更长时间地保留在缓冲池中。 表扫描(例如为 mysqldump 操作执行,或者 SELECT 带有no WHERE 子句的语句)可以将大量数据带入缓冲池并逐出相同数量的旧数据,即使新数据从未再次使用过。 类似地,由预读后台线程加载然后仅访问一次的页面移动到新列表的头部。 这些情况可以将经常使用的页面推送到旧的子列表中,在那里它们会被驱逐。 有关优化此行为的信息,请参见 第15.8.3.3节“使缓冲池扫描阻止” 第15.8.3.4节“配置InnoDB缓冲池预取(预读)”

InnoDB 标准监视器输出包含 BUFFER POOL AND MEMORY 有关缓冲池LRU算法操作 部分 中的几个字段 有关详细信息,请参阅 使用InnoDB标准监视器监视缓冲池

缓冲池配置

您可以配置缓冲池的各个方面以提高性能。

使用InnoDB标准监视器监视缓冲池

InnoDB 可以使用的标准监视器输出 SHOW ENGINE INNODB STATUS 提供有关缓冲池操作的指标。 缓冲池指标位于 标准监视器输出 BUFFER POOL AND MEMORY 部分, InnoDB 显示类似于以下内容:

----------------------
缓冲池和记忆
----------------------
分配的总大内存为2198863872
字典内存分配为776332
缓冲池大小131072
免费缓冲区124908
数据库页面5720
旧数据库页面2071
修改了db页面910
待定读数为0
待写:LRU 0,刷新列表0,单页0
页面年轻4,而不是年轻0
0.10个年轻人/秒,0.00个非年轻人/秒
页面读取197,创建5523,写入5060
0.00读/秒,190.89创建/ s,244.94写/秒
缓冲池命中率1000/1000,年轻率为0/1000没有
0/1000
页面预读0.00 / s,没有访问0.00 / s被逐出,随机读取
提前0.00 / s
LRU len:5720,unzip_LRU len:0
I / O sum [0]:cur [0],解压和[0]:cur [0]

下表描述了 InnoDB 标准监视器 报告的缓冲池指标

注意

InnoDB 标准监视器输出中 提供的每秒平均值 基于自 InnoDB 上次打印标准监视器输出 以来经过的时间

表15.2 InnoDB缓冲池度量标准

名称 描述
分配的总内存 为缓冲池分配的总内存(以字节为单位)。
分配的字典内存 InnoDB 数据字典 分配的总内存( 以字节为单位)。
缓冲池大小 分配给缓冲池的页面的总大小。
免费缓冲 缓冲池空闲列表的页面总大小。
数据库页面 缓冲池LRU列表的页面总大小。
旧数据库页面 缓冲池旧LRU子列表的页面总大小。
修改了db页面 缓冲池中修改的当前页数。
待读 等待读入缓冲池的缓冲池页数。
待写LRU 要从LRU列表底部写入的缓冲池中的旧脏页数。
待处理写入刷新列表 在检查点期间要刷新的缓冲池页数。
待写单页 缓冲池中挂起的独立页面写入次数。
页面变得年轻 缓冲池LRU列表中的年轻页总数(移动到 页面 的子列表的头部 )。
页面不年轻 缓冲池LRU列表中未完成的页面总数(保留在 子列表 中的页面, 而不是年轻)。
扬斯/秒 在缓冲池LRU列表中对旧页面的每秒平均访问次数导致页面变得年轻。 有关详细信息,请参阅此表后面的注释。
非杨氏/ s的 在缓冲池LRU列表中对旧页面的每秒平均访问次数导致不使页面变得年轻。 有关详细信息,请参阅此表后面的注释。
页面已读 从缓冲池中读取的总页数。
页面已创建 缓冲池中创建的总页数。
写的页面 从缓冲池写入的总页数。
读取/秒 每秒缓冲池页面读取的平均每秒数。
创建/秒 每秒创建的缓冲池页面的平均每秒数。
写入/秒 每秒缓冲池页面写入的平均每秒数。
缓冲池命中率 从缓冲池内存中读取的页面与从磁盘存储中读取的页面的缓冲池页面命中率。
年轻人 页面访问的平均命中率导致页面变得年轻。 有关详细信息,请参阅此表后面的注释。
不(年轻率) 页面访问的平均命中率并未导致页面变得年轻。 有关详细信息,请参阅此表后面的注释。
页面预读 每秒预读操作的平均值。
被删除的页面无法访问 在没有从缓冲池访问的情况下被逐出的页面的每秒平均值。
随机预读 随机预读操作的每秒平均值。
LRU len 缓冲池LRU列表的页面总大小。
unzip_LRU len 缓冲池的总页面大小unzip_LRU列表。
I / O总和 访问的缓冲池LRU列表页面总数,最近50秒。
I / O cur 访问的缓冲池LRU列表页面的总数。
I / O解压缩总和 访问的缓冲池unzip_LRU列表页面总数。
I / O解压缩 访问的缓冲池unzip_LRU列表页面总数。

备注

  • youngs/s 指标仅适用于旧页面。 它基于页面访问次数而不是页面数。 可以对给定页面进行多次访问,所有这些访问都被计算在内。 如果 youngs/s 在没有发生大型扫描时 看到非常低的 值,则可能需要减少延迟时间或增加用于旧子列表的缓冲池的百分比。 增加百分比使旧的子列表变大,因此该子列表中的页面需要更长的时间才能移动到尾部,这增加了再次访问这些页面并使其变得年轻的可能性。

  • non-youngs/s 指标仅适用于旧页面。 它基于页面访问次数而不是页面数。 可以对给定页面进行多次访问,所有这些访问都被计算在内。 如果 non-youngs/s 在执行大型表扫描时 没有看到更高的 值(并且 youngs/s 更高 ),请增加延迟值。

  • young-making 速率考虑了对所有缓冲池页面的访问,而不仅仅是访问旧子列表中的页面。 young-making 速度和 not 速率通常不加起来的整体缓冲池命中率。 旧子列表中的页面命中会导致页面移动到新的子列表,但是新子列表中的页面命中会导致页面仅在距离头部一定距离时才移动到列表的头部。

  • not (young-making rate) 是由于 innodb_old_blocks_time 未被满足 定义的延迟 ,或者由于新子列表中的页面命中没有导致页面被移动到头部 而导致页面访问没有导致页面年轻化的平均命中率 此速率考虑了对所有缓冲池页面的访问,而不仅仅是访问旧子列表中的页面。

缓冲池 服务器状态变量 INNODB_BUFFER_POOL_STATS 表提供了许多在 InnoDB 标准监视器输出中 找到的相同缓冲池指标 有关更多信息,请参见 例15.10“查询INNODB_BUFFER_POOL_STATS表”

15.5.2更改缓冲区

更改缓冲区是一种特殊的数据结构, 当这些页面不在 缓冲池中 ,它会更改 二级索引 页面 缓冲的变化,这可能导致从 当页面被加载到由其他的读操作缓冲池操作(DML),将在后面合并。 INSERT UPDATE DELETE

图15.3更改缓冲区

Content is described in the surrounding text.

聚簇索引 不同 ,二级索引通常不是唯一的,并且插入二级索引的顺序相对随机。 同样,删除和更新可能会影响不在索引树中相邻的二级索引页。 当受影响的页面被其他操作读入缓冲池时,合并缓存的更改,避免了从磁盘读取二级索引页到缓冲池所需的大量随机访问I / O.

系统大部分空闲时或在慢速关闭期间运行的清除操作会定期将更新的索引页写入磁盘。 与每个值立即写入磁盘相比,清除操作可以更有效地为一系列索引值写入磁盘块。

当有许多受影响的行和许多要更新的辅助索引时,更改缓冲区合并可能需要几个小时。 在此期间,磁盘I / O会增加,这会导致磁盘绑定查询显着减慢。 提交事务后,甚至在服务器关闭并重新启动之后,更改缓冲区合并也可能继续发生( 有关更多信息 请参见 第15.20.2节“强制InnoDB恢复” )。

在内存中,更改缓冲区占用缓冲池的一部分。 在磁盘上,更改缓冲区是系统表空间的一部分,其中在关闭数据库服务器时缓冲索引更改。

变更缓冲区中缓存的数据类型由 innodb_change_buffering 变量控制。 有关更多信息,请参阅 配置更改缓冲 您还可以配置最大更改缓冲区大小。 有关更多信息,请参阅 配置更改缓冲区最大大小

如果索引包含降序索引列或主键包含降序索引列,则辅助索引不支持更改缓冲。

有关更改缓冲区的 常见问题解答 ,请参见 第A.15节“MySQL 8.0常见问题解答:InnoDB更改缓冲区”

配置更改缓冲

对表执行 何时 INSERT UPDATE DELETE 操作 索引列的值(特别是辅助键的值)通常按未排序顺序排列,需要大量I / O才能使二级索引更新。 变化缓冲区 当相关缓存变为二级索引条目 页面 不在 缓冲池 ,从而通过从磁盘上的页面不会立即读避免了昂贵的I / O操作。 当页面加载到缓冲池中时,将合并缓冲的更改,稍后将更新的页面刷新到磁盘。 InnoDB 主线程在服务器几乎空闲时以及在 慢速关闭 期间合并缓冲的更改

因为它可以减少磁盘读取和写入,所以更改缓冲区功能对于I / O绑定的工作负载最有价值,例如具有大量DML操作的应用程序(如批量插入)。

但是,更改缓冲区占用缓冲池的一部分,从而减少了可用于缓存数据页的内存。 如果工作集几乎适合缓冲池,或者您的表具有相对较少的二级索引,则禁用更改缓冲可能很有用。 如果工作数据集完全适合缓冲池,则更改缓冲不会产生额外开销,因为它仅适用于不在缓冲池中的页面。

您可以 InnoDB 使用 innodb_change_buffering 配置参数 控制 执行更改缓冲 的范围 您可以为插入,删除操作(当索引记录最初标记为删除时)和清除操作(物理删除索引记录时)启用或禁用缓冲。 更新操作是插入和删除的组合。 默认 innodb_change_buffering 值为 all

允许的 innodb_change_buffering 值包括:

  • all

    默认值:缓冲区插入,删除标记操作和清除。

  • none

    不要缓冲任何操作。

  • inserts

    缓冲插入操作。

  • deletes

    缓冲区删除标记操作。

  • changes

    缓冲插入和删除标记操作。

  • purges

    缓冲后台发生的物理删除操作。

您可以 innodb_change_buffering 在MySQL选项文件( my.cnf my.ini )中 设置 参数, 也可以使用 SET GLOBAL 语句 动态更改 参数 ,该 语句需要足以设置全局系统变量的权限。 请参见 第5.1.9.1节“系统变量权限” 更改设置会影响新操作的缓冲; 现有缓冲条目的合并不受影响。

配置更改缓冲区最大大小

innodb_change_buffer_max_size 变量允许将更改缓冲区的最大大小配置为缓冲池总大小的百分比。 默认情况下, innodb_change_buffer_max_size 设置为25.最大设置为50。

考虑增加 innodb_change_buffer_max_size 具有大量插入,更新和删除活动的MySQL服务器,其中更改缓冲区合并无法跟上新的更改缓冲区条目,导致更改缓冲区达到其最大大小限制。

考虑 innodb_change_buffer_max_size 使用用于报告的静态数据在MySQL服务器上 减少 ,或者如果更改缓冲区消耗了与缓冲池共享的太多内存空间,导致页面比预期更早地超出缓冲池。

使用代表性工作负载测试不同设置以确定最佳配置。 innodb_change_buffer_max_size 设置是动态的,允许在不重新启动服务器的情况下修改设置。

监控变更缓冲区

以下选项可用于更改缓冲区监视:

  • InnoDB 标准监视器输出包括更改缓冲区状态信息 要查看监视器数据,请发出 SHOW ENGINE INNODB STATUS 语句。

    MySQL的> SHOW ENGINE INNODB STATUS\G
    

    更改缓冲区状态信息位于 INSERT BUFFER AND ADAPTIVE HASH INDEX 标题 下, 并显示类似于以下内容:

    -------------------------------------
    插入缓冲区和自适应哈希索引
    -------------------------------------
    Ibuf:size 1,free list len 0,seg size 2,0合并
    合并后的业务:
     插入0,删除标记0,删除0
    丢弃的操作:
     插入0,删除标记0,删除0
    散列表大小4425293,使用单元格32,节点堆有1个缓冲区
    13577.57哈希搜索/ s,202.47非哈希搜索/ s
    

    有关更多信息,请参见 第15.16.3节“InnoDB标准监视器和锁定监视器输出”

  • INFORMATION_SCHEMA.INNODB_METRICS 表提供了 InnoDB 标准监视器输出中的 大多数数据点 以及其他数据点。 要查看更改缓冲区指标及其各自的说明,请发出以下查询:

    MySQL的> SELECT NAME, COMMENT FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME LIKE '%ibuf%'\G
    

    有关 INNODB_METRICS 表用法信息,请参见 第15.14.6节“InnoDB INFORMATION_SCHEMA度量表”

  • INFORMATION_SCHEMA.INNODB_BUFFER_PAGE 表提供有关缓冲池中每个页面的元数据,包括更改缓冲区索引和更改缓冲区位图页面。 更改缓冲区页面由标识 PAGE_TYPE IBUF_INDEX 是更改缓冲区索引页 IBUF_BITMAP 的页面类型,是更改缓冲区位图页的页面类型。

    警告

    查询 INNODB_BUFFER_PAGE 表可能会带来显着的性能开销。 为避免影响性能,请在测试实例上重现要调查的问题,并在测试实例上运行查询。

    例如,您可以查询 INNODB_BUFFER_PAGE 表以确定大致 缓冲池页面的百分比 IBUF_INDEX IBUF_BITMAP 页面 的大致数量

    MySQL的> SELECT (SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
           WHERE PAGE_TYPE LIKE 'IBUF%') AS change_buffer_pages, 
           (SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE) AS total_pages,
           (SELECT ((change_buffer_pages/total_pages)*100)) 
           AS change_buffer_page_percentage;
    + --------------------- + ------------- ------------- + ------------------ +
    | change_buffer_pages | total_pages | change_buffer_page_percentage |
    + --------------------- + ------------- ------------- + ------------------ +
    | 25 | 8192 | 0.3052 |
    + --------------------- + ------------- ------------- + ------------------ +
    

    有关该 INNODB_BUFFER_PAGE 提供的其他数据的信息 ,请参见 第25.39.1节“INFORMATION_SCHEMA INNODB_BUFFER_PAGE表” 有关相关用法信息,请参见 第15.14.5节“InnoDB INFORMATION_SCHEMA缓冲池表”

  • Performance Schema 为高级性能监视提供更改缓冲区互斥等待检测。 要查看更改缓冲区检测,请发出以下查询:

    MySQL的> SELECT * FROM performance_schema.setup_instruments
           WHERE NAME LIKE '%wait/synch/mutex/innodb/ibuf%';
    + ------------------------------------------------- ------ + --------- + ------- +
    | NAME | 启用| 定时|
    + ------------------------------------------------- ------ + --------- + ------- +
    | wait / synch / mutex / innodb / ibuf_bitmap_mutex | 是的| 是的|
    | wait / synch / mutex / innodb / ibuf_mutex | 是的| 是的|
    | wait / synch / mutex / innodb / ibuf_pessimistic_insert_mutex | 是的| 是的|
    + ------------------------------------------------- ------ + --------- + ------- +
    

    有关监视 InnoDB 互斥锁等待的信息,请参见 第15.15.2节“使用性能架构监视InnoDB Mutex等待”

15.5.3自适应哈希索引

自适应散列索引功能使得能够 InnoDB 在具有适当的工作负载组合和缓冲池足够内存的系统上执行更像内存数据库,而不会牺牲事务特性或可靠性。 自适应哈希索引功能由 innodb_adaptive_hash_index 变量 启用 ,或在服务器启动时关闭 --skip-innodb-adaptive-hash-index

基于观察到的搜索模式,使用索引键的前缀构建哈希索引。 前缀可以是任何长度,并且可能只有B树中的某些值出现在哈希索引中。 哈希索引是根据需要经常访问的索引页面构建的。

如果表几乎完全适合主内存,则哈希索引可以通过启用任何元素的直接查找来加速查询,将索引值转换为一种指针。 InnoDB 有一个监视索引搜索的机制。 如果 InnoDB 通知查询可以从构建哈希索引中受益,则会自动执行此操作。

对于某些工作负载,哈希索引查找的加速大大超过了监视索引查找和维护哈希索引结构的额外工作。 在高负载(例如多个并发连接)下,对自适应哈希索引的访问有时会成为争用的来源。 查询与 LIKE 运营商和 % 通配符也往往不会受益。 对于无法从自适应哈希索引功能中受益的工作负载,将其关闭可减少不必要的性能开销。 由于很难预先预测自适应散列索引功能是否适合特定系统和工作负载,因此请考虑在启用和禁用运行基准测试时运行基准测试。 MySQL 5.6中的体系结构更改使其更适合禁用自适应哈希索引功能,而不是早期版本。

自适应哈希索引功能已分区。 每个索引都绑定到一个特定的分区,每个分区都由一个单独的锁存器保护。 分区由 innodb_adaptive_hash_index_parts 变量 控制 innodb_adaptive_hash_index_parts 默认情况下, 变量设置为8。 最大设置为512。

您可以在 输出 SEMAPHORES 部分中 监视自适应哈希索引的使用和争用 SHOW ENGINE INNODB STATUS 如果有许多线程正在等待创建的RW锁存器 btr0sea.c ,请考虑增加自适应哈希索引分区的数量或禁用自适应哈希索引功能。

有关哈希索引的性能特征的信息,请参见 第8.3.9节“B树和哈希索引的比较”

15。5。4日志缓冲区

日志缓冲区是保存要写入磁盘上日志文件的数据的内存区域。 日志缓冲区大小由 innodb_log_buffer_size 变量 定义 默认大小为16MB。 日志缓冲区的内容会定期刷新到磁盘。 大型日志缓冲区使大型事务能够运行,而无需在事务提交之前将重做日志数据写入磁盘。 因此,如果您有更新,插入或删除许多行的事务,则增加日志缓冲区的大小可以节省磁盘I / O.

innodb_flush_log_at_trx_commit 变量控制如何写入日志缓冲区的内容并刷新到磁盘。 innodb_flush_log_at_timeout 变量控制日志刷新频率。

有关相关信息,请参阅 内存配置 第8.5.4节“优化InnoDB重做日志记录”

15.6 InnoDB磁盘结构

本节介绍 InnoDB 磁盘结构和相关主题。

15.6.1表格

本节介绍与 InnoDB 相关的主题

15.6.1.1创建InnoDB表

要创建 InnoDB 表,请使用该 CREATE TABLE 语句。

CREATE TABLE t1(INT,b CHAR(20),PRIMARY KEY(a))ENGINE = InnoDB;

ENGINE=InnoDB 如果 InnoDB 定义为默认存储引擎, 不需要指定 子句 要检查默认存储引擎,请发出以下语句:

MySQL的> SELECT @@default_storage_engine;
+ -------------------------- +
| @@ default_storage_engine |
+ -------------------------- +
| InnoDB |
+ -------------------------- +

ENGINE=InnoDB 如果您计划使用 mysqldump 或复制来重放 CREATE TABLE 默认存储引擎不在的服务器上的语句, 您仍可以使用 子句 InnoDB

一个 InnoDB 表及其索引可以在创建 系统表空间 ,在一个 文件中,每个表 的表空间,或在 一般的表空间 如果 innodb_file_per_table 启用(默认值),则会 InnoDB 在单个每个表的文件表空间中隐式创建一个表。 相反, innodb_file_per_table 禁用时,会 InnoDB InnoDB 系统表空间中 隐式创建 表。 要在通用表空间中创建表,请使用 CREATE TABLE ... TABLESPACE 语法。 有关更多信息,请参见 第15.6.3.3节“常规表空间”

当您在每个表的文件表空间中创建一个 表时,默认情况下 ,MySQL会 在MySQL数据目录下的数据库目录中 创建一个 .ibd 表空间文件。 InnoDB 系统表空间中创建的表是在现有的 ibdata文件中 创建的,该 文件 位于MySQL数据目录中。 在通用表空间中创建的表在现有的通用表空间 .ibd文件中创建 可以在MySQL数据目录的内部或外部创建常规表空间文件。 有关更多信息,请参见 第15.6.3.3节“常规表空间”

在内部, InnoDB 将每个表的条目添加到数据字典中。 该条目包括数据库名称。 例如,如果 t1 test 数据库中 创建了 表,则数据库名称的数据字典条目为 'test/t1' 这意味着您可以 t1 在不同的数据库中 创建具有相同名称( )的表,并且表名不会在内部发生冲突 InnoDB

InnoDB表格和行格式

InnoDB 的默认行格式 innodb_default_row_format 配置选项 定义 ,其默认值为 DYNAMIC Dynamic Compressed 行格式允许您利用 InnoDB 表压缩和长列值的高效页外存储等功能。 要使用这些行格式, innodb_file_per_table 必须启用(默认值)。

SET GLOBAL innodb_file_per_table = 1;
CREATE TABLE t3(INT,b CHAR(20),PRIMARY KEY(a))ROW_FORMAT = DYNAMIC;
CREATE TABLE t4(INT,b CHAR(20),PRIMARY KEY(a))ROW_FORMAT = COMPRESSED;

或者,您可以使用 CREATE TABLE ... TABLESPACE 语法 InnoDB 在常规表空间中 创建 表。 常规表空间支持所有行格式。 有关更多信息,请参见 第15.6.3.3节“常规表空间”

CREATE TABLE t1(c1 INT PRIMARY KEY)TABLESPACE ts1 ROW_FORMAT = DYNAMIC;

CREATE TABLE ... TABLESPACE 语法还可用于 在系统表空间中 创建 InnoDB 具有 Dynamic 行格式的表,以及具有 Compact Redundant 行格式的

CREATE TABLE t1(c1 INT PRIMARY KEY)TABLESPACE = innodb_system ROW_FORMAT = DYNAMIC;

有关 InnoDB 行格式的 更多信息 ,请参见 第15.10节“InnoDB行格式” 有关如何确定 InnoDB 的行格式 InnoDB 行格式 的物理特性 ,请参见 第15.10节“InnoDB行格式”

InnoDB表和主键

始终 定义 主键 InnoDB ,指定以下列:

  • 被最重要的查询引用。

  • 永远不会留空。

  • 永远不会有重复的值。

  • 很少,如果一旦插入就改变价值。

例如,在包含有关人员信息的表格中,您不会创建主键, (firstname, lastname) 因为多个人可以使用相同的名称,有些人使用空白姓氏,有时人们会更改其姓名。 由于存在如此多的约束,通常没有一组明显的列用作主键,因此您创建一个带有数字ID的新列作为主键的全部或部分。 您可以声明一个 自动增量 列,以便在插入行时自动填充升序值:

#ID的值可以像不同表中相关项之间的指针一样。
CREATE TABLE t5(id INT AUTO_INCREMENT,b CHAR(20),PRIMARY KEY(id));

#主键可以包含多个列。任何autoinc列都必须先行。
CREATE TABLE t6(id INT AUTO_INCREMENT,INT,b CHAR(20),PRIMARY KEY(id,a));

尽管该表在没有定义主键的情况下正常工作,但主键涉及性能的许多方面,并且是任何大型或经常使用的表的关键设计方面。 建议您始终在 CREATE TABLE 语句中 指定主键 如果您创建表,加载数据,然后运行 ALTER TABLE 以稍后添加主键,则该操作比创建表时定义主键要慢得多。

查看InnoDB表属性

要查看 InnoDB 的属性 ,请发出以下 SHOW TABLE STATUS 语句:

MySQL的> SHOW TABLE STATUS FROM test LIKE 't%' \G;
*************************** 1。排******************** *******
           姓名:t1
         引擎:InnoDB
        版本:10
     Row_format:紧凑
           行:0
 Avg_row_length:0
    Data_length:16384
Max_data_length:0
   Index_length:0
      Data_free:0
 Auto_increment:NULL
    Create_time:2015-03-16 15:13:31
    Update_time:NULL
     Check_time:NULL
      排序规则:utf8mb4_0900_ai_ci
       校验和:NULL
 Create_options:
        评论:

有关 SHOW TABLE STATUS 输出的 信息 ,请参见 第13.7.6.36节“显示表状态语法”

InnoDB 也可以使用 InnoDB Information Schema系统表 查询表属性

MySQL的> SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLES WHERE NAME='test/t1' \G
*************************** 1。排******************** *******
     TABLE_ID:45
         姓名:test / t1
         标志:1
       N_COLS:5
        空间:35
   ROW_FORMAT:紧凑
ZIP_PAGE_SIZE:0
   SPACE_TYPE:单身

有关更多信息,请参见 第15.14.3节“InnoDB INFORMATION_SCHEMA架构对象表”

15.6.1.2移动或复制InnoDB表

本节介绍将一些或所有 InnoDB 移动或复制 到其他服务器或实例的技术。 例如,您可以将整个MySQL实例移动到更大,更快的服务器; 您可以将整个MySQL实例克隆到新的复制从属服务器; 您可以将单个表复制到另一个实例以开发和测试应用程序,或者复制到数据仓库服务器以生成报告。

在Windows上, InnoDB 始终以小写形式在内部存储数据库和表名。 要以二进制格式将数据库从Unix移动到Windows或从Windows移动到Unix,请使用小写名称创建所有数据库和表。 一种方便的方法是 在创建任何数据库或表之前将以 下行添加到 文件 [mysqld] 部分 my.cnf my.ini

的[mysqld]
的lower_case_table_names = 1
注意

禁止 lower_case_table_names 使用与初始化 服务器时使用的 设置不同的设置启动服务器。

移动或复制 InnoDB 表格的 技巧 包括:

可传输的表空间

可传输表空间功能用于 FLUSH TABLES ... FOR EXPORT 准备 InnoDB 表,以便从一个服务器实例复制到另一个服务器实例。 要使用此功能, InnoDB 必须使用 innodb_file_per_table set 创建表 ON 以便每个 InnoDB 表都有自己的表空间。 有关用法信息,请参见 第15.6.3.7节“将表空间复制到另一个实例”

MySQL企业备份

MySQL Enterprise Backup产品允许您备份正在运行的MySQL数据库,同时最大限度地减少对操作的干扰,同时生成数据库的一致快照。 当MySQL Enterprise Backup复制表时,可以继续读取和写入。 此外,MySQL Enterprise Backup可以创建压缩备份文件,并备份表的子集。 结合MySQL二进制日志,您可以执行时间点恢复。 MySQL Enterprise Backup作为MySQL Enterprise订阅的一部分包含在内。

有关MySQL Enterprise Backup的更多详细信息,请参见 第30.2节“MySQL Enterprise Backup概述”

复制数据文件(冷备份方法)

InnoDB 只需复制 第15.17.1节“InnoDB备份”中 “冷备份”下列出的所有相关文件, 即可移动 数据库

InnoDB 数据和日志文件在具有相同浮点数格式的所有平台上是二进制兼容的。 如果浮点格式不同,但是你有没有使用 FLOAT DOUBLE 在您的表中的数据类型,则过程是一样:简单地拷贝相关文件。

移动或复制每个 .ibd 文件的文件时,源系统和目标系统上的数据库目录名必须相同。 存储在 InnoDB 共享表空间中 的表定义 包括数据库名称。 存储在表空间文件中的事务ID和日志序列号在数据库之间也不同。

要将 .ibd 文件和关联表从一个数据库移动到另一个数据库,请使用以下 RENAME TABLE 语句:

RENAME TABLE db1.tbl_nameTO db2.tbl_name;

如果您对文件进行了 干净 备份 .ibd ,则可以将其还原到源自它的MySQL安装,如下所示:

  1. 自复制 .ibd 文件 以来,不得删除或截断 该表,因为这样做会更改存储在表空间内的表ID。

  2. 发出此 ALTER TABLE 语句以删除当前 .ibd 文件:

    ALTER TABLE tbl_nameDISCARD TABLESPACE;
    
  3. 将备份 .ibd 文件 复制 到正确的数据库目录。

  4. 发出此 ALTER TABLE 语句告诉 InnoDB 使用 .ibd 的新 文件:

    ALTER TABLE tbl_nameIMPORT TABLESPACE;
    
    注意

    ALTER TABLE ... IMPORT TABLESPACE 功能不会对导入的数据强制执行外键约束。

在此上下文中, 干净 .ibd 文件备份是满足以下要求的备份:

  • .ibd 文件中 的事务没有未提交的修改

  • .ibd 文件 中没有未合并的插入缓冲区条目

  • Purge已从 .ibd 文件中 删除了所有删除标记的索引记录

  • mysqld 已将 .ibd 文件的 所有已修改页面 从缓冲池 刷新 到文件。

您可以 .ibd 使用以下方法 创建一个干净的备份 文件:

  1. 停止 mysqld 服务器中的 所有活动 并提交所有事务。

  2. 等到 SHOW ENGINE INNODB STATUS 显示数据库中没有活动事务,并且主线程状态 InnoDB Waiting for server activity 然后,您可以制作该 .ibd 文件 的副本

制作 .ibd 文件 的干净副本的另一种方法 是使用MySQL Enterprise Backup产品:

  1. 使用MySQL Enterprise Backup备份 InnoDB 安装。

  2. 在备份上 启动第二个 mysqld 服务器,让它清理备份中的 .ibd 文件。

导出和导入(mysqldump)

您可以使用 mysqldump 将表转储到一台计算机上,然后在另一台计算机上导入转储文件。 使用此方法,格式是否不同或表是否包含浮点数据无关紧要。

提高此方法性能的一种方法是 在导入数据时 关闭 自动提交 模式,假设表空间有足够的空间用于导入事务生成的大回滚段。 仅在导入整个表或表的一部分后进行提交。

15.6.1.3将表从MyISAM转换为InnoDB

如果您 MyISAM 要转换表格以 InnoDB 获得更好的可靠性和可扩展性,请在转换之前查看以下指南和提示。

注意

MyISAM 在以前版本的MySQL中创建的 分区 表与MySQL 8.0不兼容。 这些表必须在升级之前准备好,方法是删除分区,或者将它们转换为 InnoDB 有关 更多信息 请参见 第23.6.2节“分区与存储引擎相关的限制”

调整MyISAM和InnoDB的内存使用情况

当您从 MyISAM 表中 转换时 ,请将 key_buffer_size 配置选项 的值降低 为释放结果不再需要的空闲内存。 增加 innodb_buffer_pool_size 配置选项 的值,该 选项执行为 InnoDB 分配高速缓存的类似角色 InnoDB 缓冲池 可以缓存表数据和索引数据,加快了查询,查找并保持查询结果在内存中进行再利用。 有关缓冲池大小配置的指导,请参见 第8.12.3.1节“MySQL如何使用内存”

处理太长或太短的交易

因为 MyISAM 表不支持 事务 ,所以您可能没有太多关注 autocommit 配置选项和 COMMIT ROLLBACK 语句。 这些关键字对于允许多个会话同时读取和写入 InnoDB 非常重要 ,从而在写入繁重的工作负载中提供了显着的可伸缩性优势。

当事务处于打开状态时,系统会在事务开始时保留数据的快照,如果系统在杂散事务保持运行时插入,更新和删除数百万行,则会导致大量开销。 因此,请注意避免运行时间过长的事务:

  • 如果您正在使用 mysql 会话进行交互式实验,请 COMMIT 在完成后 始终 (完成更改)或 ROLLBACK (撤消更改)。 关闭交互式会话,而不是让它们长时间保持打开状态,以避免事务长时间保持交易。

  • 确保应用程序中的任何错误处理程序也未 ROLLBACK 完成更改或 COMMIT 已完成更改。

  • ROLLBACK 是一个相对昂贵的操作,因为 INSERT UPDATE DELETE 操作被写入 InnoDB 表之前 COMMIT ,期望大多数更改成功提交并且回滚很少。 在试验大量数据时,请避免对大量行进行更改,然后回滚这些更改。

  • 使用一系列 INSERT 语句 加载大量数据时 ,请定期 COMMIT 检查结果,以避免持续数小时的事务。 在数据仓库的典型加载操作中,如果出现问题,则截断表(使用 TRUNCATE TABLE )并从头开始而不是执行 ROLLBACK

前面的提示可以节省在过长的事务中可能浪费的内存和磁盘空间。 当事务比它们应该更短时,问题是I / O过多。 对于每个 COMMIT ,MySQL确保每个更改都安全地记录到磁盘,这涉及一些I / O.

  • 对于 InnoDB 上的大多数操作 ,您应该使用该设置 autocommit=0 从效率的角度看,这样就避免了在发出大量连续的不必要的I / O INSERT UPDATE DELETE 语句。 从安全角度来看, ROLLBACK 如果您在 mysql 命令行或应用程序中的异常处理程序中 出错 ,这允许您发出 声明以恢复丢失或乱码的数据

  • autocommit=1 适用于 InnoDB 的时间 是在运行一系列查询以生成报告或分析统计信息时。 在这种情况下,没有与 COMMIT 相关的I / O代价 ROLLBACK ,并且 InnoDB 可以 自动优化只读工作负载

  • 如果进行了一系列相关更改,请在最后一次完成所有更改 COMMIT 例如,如果将相关的信息片段插入到多个表中,请 COMMIT 在进行所有更改后 执行单个操作 或者,如果您运行多个连续 INSERT 语句,请 COMMIT 在加载所有数据后 执行单个语句 ; 如果您正在进行数百万条 INSERT 语句,可能会通过发出 COMMIT 每万或数十万条记录来 分割 大额交易,因此交易不会变得太大。

  • 请记住,即使 SELECT 语句 也会 打开一个事务,因此在交互式 mysql 会话中 运行某些报表或调试查询后 ,可以发出 COMMIT 或关闭 mysql 会话。

处理死锁

您可能会 在MySQL错误日志或输出中 看到引用 死锁 ”的 警告消息 SHOW ENGINE INNODB STATUS 尽管名称听起来可怕,但 死锁 并不是 InnoDB 表格 的严重问题 ,通常不需要任何纠正措施。 当两个事务开始修改多个表,以不同的顺序访问表时,它们可以达到每个事务等待另一个事务的状态,并且两者都不能继续。 启用 死锁检测 (默认)时,MySQL立即检测到这种情况并取消( 回滚 较小 交易,让对方继续。 如果使用 innodb_deadlock_detect 配置选项 禁用死锁检测 ,则 InnoDB 依赖于 innodb_lock_wait_timeout 设置在发生死锁时回滚事务。

无论哪种方式,您的应用程序都需要错误处理逻辑来重新启动由于死锁而被强制取消的事务。 当您重新发出与以前相同的SQL语句时,原始计时问题不再适用。 另一个事务已经完成,您的事务可以继续,或者另一个事务仍在进行中,您的事务将等待直到完成。

如果持续发生死锁警告,您可以查看应用程序代码以一致的方式重新排序SQL操作,或缩短事务。 您可以使用 innodb_print_all_deadlocks 启用 选项 进行测试, 以查看MySQL错误日志中的所有死锁警告,而不仅仅是 SHOW ENGINE INNODB STATUS 输出中 的最后一个警告

有关更多信息,请参见 第15.7.5节“InnoDB中的死锁”

规划存储布局

要从 InnoDB 表中 获得最佳性能 ,您可以调整与存储布局相关的许多参数。

当您将 MyISAM 是大的,经常访问的,并保持至关重要的数据表,调查和考虑 innodb_file_per_table innodb_page_size 配置选项,以及 ROW_FORMAT KEY_BLOCK_SIZE 条款 中的 CREATE TABLE 说法。

在最初的实验中,最重要的设置是 innodb_file_per_table 启用此设置(默认设置)后,将 InnoDB 每个表的文件表 空间 中隐式创建 InnoDB 系统表空间相比,每个表的表空间允许在截断或删除表时由操作系统回收磁盘空间。 每个表的文件表空间还支持 DYNAMIC COMPRESSED 行格式以及相关的功能,例如表压缩,长可变长度列的高效页外存储以及大索引前缀。 有关更多信息,请参阅 第15.6.3.2节“每个表的文件表空间”

您还可以将 InnoDB 存储 在共享通用表空间中,该表空间支持多个表和所有行格式。 有关更多信息,请参见 第15.6.3.3节“常规表空间”

转换现有表

要将非 InnoDB 转换 为使用,请 InnoDB 使用 ALTER TABLE

ALTER TABLE table_nameENGINE = InnoDB;
克隆表的结构

您可以创建一个 InnoDB 表,它是MyISAM表的克隆,而不是 ALTER TABLE 用于执行转换,以在切换之前并排测试旧表和新表。

创建 InnoDB 具有相同列和索引定义 的空 表。 使用 看到完整的 语句中使用。 子句 更改 SHOW CREATE TABLE table_name\G CREATE TABLE ENGINE ENGINE=INNODB

传输现有数据

要将大量数据传输到 InnoDB 如上一节所示创建 的空 表中,请插入行 INSERT INTO innodb_table SELECT * FROM myisam_table ORDER BY primary_key_columns

您还可以 InnoDB 在插入数据后 创建索引 从历史上看,创建新的二级索引对InnoDB来说是一个缓慢的操作,但现在您可以在加载数据后创建索引,而索引创建步骤的开销相对较小。

如果您 UNIQUE 对辅助密钥 约束,则可以通过在导入操作期间临时关闭唯一性检查来加速表导入:

SET unique_checks = 0;
... import operation ...
SET unique_checks = 1;

对于大表,这可以节省磁盘I / O,因为 InnoDB 可以使用其 更改缓冲区 将二级索引记录作为批处理写入。 确保数据不包含重复键。 unique_checks 允许但不要求存储引擎忽略重复键。

为了更好地控制插入过程,您可以插入大表:

INSERT INTO newtable SELECT * FROM oldtable
   你的钥匙> something和你的钥匙<= somethingelse;

插入所有记录后,您可以重命名表。

在转换大表期间,增加 InnoDB 缓冲池 的大小 以减少磁盘I / O,最大为物理内存的80%。 您还可以增加 InnoDB 日志文件 的大小

存储要求

如果您打算 InnoDB 在转换过程中 表中创建 数据的多个临时副本, 建议您在每个表的文件表空间中创建表,以便在删除表时可以回收磁盘空间。 innodb_file_per_table 配置选项启用(默认),新创建的 InnoDB 表在文件的每个表的表空间隐式创建。

无论是 MyISAM 直接 转换 表还是创建克隆 InnoDB 表,请确保在此过程中有足够的磁盘空间来容纳旧表和新表。 InnoDB 表需要比 MyISAM 更多的磁盘空间 如果 ALTER TABLE 操作空间不足,则会启动回滚,如果磁盘受限,则可能需要数小时。 对于插入, InnoDB 使用插入缓冲区将二级索引记录批量合并到索引中。 这节省了大量的磁盘I / O. 对于回滚,不使用此类机制,并且回滚可能比插入时间长30倍。

在失控回滚的情况下,如果数据库中没有有价值的数据,则建议终止数据库进程,而不是等待数百万个磁盘I / O操作完成。 有关完整的过程,请参见 第15.20.2节“强制InnoDB恢复”

为每个表定义一个主键

PRIMARY KEY 子句是影响MySQL查询性能以及表和索引的空间使用的关键因素。 主键唯一标识表中的行。 表中的每一行都必须具有主键值,并且没有两行可以具有相同的主键值。

这些是主键的准则,然后是更详细的解释。

  • PRIMARY KEY 为每个表 声明一个 通常,它是 WHERE 查找单行时 子句中 引用的最重要的列

  • PRIMARY KEY 在原始 CREATE TABLE 语句中 声明该 子句 ,而不是稍后通过 ALTER TABLE 语句 添加它

  • 仔细选择列及其数据类型。 首选数字列而不是字符或字符串。

  • 如果没有要使用的另一个稳定,唯一,非空的数字列,请考虑使用自动增量列。

  • 如果对主键列的值是否可能发生变化有任何疑问,自动增量列也是一个不错的选择。 更改主键列的值是一项昂贵的操作,可能涉及重新排列表中和每个二级索引中的数据。

考虑将 主键 添加 到任何尚未拥有的表中。 根据表格的最大投影尺寸使用最小的实际数字类型。 这可以使每一排稍微紧凑,这可以为大型桌子节省大量空间。 如果表具有任何 二级索引 则节省的空间将成倍增加 ,因为主键值在每个二级索引条目中重复。 除了减少磁盘上的数据大小之外,一个小的主键还可以让更多数据适合 缓冲池 ,从而加速各种操作并提高并发性。

如果表已经在某个较长的列(例如a)上具有主键 VARCHAR ,请考虑添加新的无符号 AUTO_INCREMENT 列并将主键切换到该列,即使查询中未引用该列也是如此。 这种设计变更可以在二级指标中节省大量空间。 您可以指定以前的主键列, UNIQUE NOT NULL 以强制执行与 PRIMARY KEY 子句 相同的约束 ,即防止所有这些列中出现重复或空值。

如果跨多个表传播相关信息,通常每个表对其主键使用相同的列。 例如,人员数据库可能有多个表,每个表都有一个员工编号的主键。 销售数据库可能有一些表具有客户编号的主键,而其他表具有订货号的主键。 因为使用主键的查找速度非常快,所以可以为这些表构建有效的连接查询。

如果你 PRIMARY KEY 完全 抛弃该 条款,MySQL会为你创建一个看不见 子句。 它是一个6字节的值,可能比您需要的长,因此浪费空间。 因为它是隐藏的,所以您无法在查询中引用它。

应用程序性能注意事项

可靠性和可伸缩性功能 InnoDB 需要比同等 MyISAM 更多的磁盘存储 您可以稍微更改列和索引定义,以便在处理结果集时更好地利用空间,减少I / O和内存消耗,以及更有效地使用索引查找的更好的查询优化计划。

如果确实为主键设置了数字ID列,请使用该值与任何其他表中的相关值进行交叉引用,尤其是对于 连接 查询。 例如,不是接受国家/地区名称作为输入并执行搜索相同名称的查询,而是执行一次查找以确定国家/地区ID,然后执行其他查询(或单个连接查询)以在多个表中查找相关信息。 不是将客户或目录项编号存储为数字字符串,而是使用几个字节,将其转换为数字ID以进行存储和查询。 4字节无符号 INT 专栏可以索引超过40亿件物品(美国含义为10亿:1000万)。 有关不同整数类型的范围,请参见 第11.2.1节“整数类型(精确值) - INTEGER,INT,SMALLINT,TINYINT,MEDIUMINT,BIGINT”

了解与InnoDB表关联的文件

InnoDB 文件需要比 MyISAM 文件 更多的关注和规划

15.6.1.4 InnoDB中的AUTO_INCREMENT处理

InnoDB 提供了一种可配置的锁定机制,可以显着提高SQL语句的可伸缩性和性能,从而为具有 AUTO_INCREMENT 列的 表添加行 要将该 AUTO_INCREMENT 机制与 InnoDB 一起使用 AUTO_INCREMENT 必须将列定义为索引的一部分,以便可以 在表上 执行等效的索引 查找以获取最大列值。 通常,这是通过使列成为某些表索引的第一列来实现的。 SELECT MAX(ai_col)

本节介绍 AUTO_INCREMENT 锁定模式 的行为, 不同 AUTO_INCREMENT 锁定模式设置的 使用含义 以及如何 InnoDB 初始化 AUTO_INCREMENT 计数器。

InnoDB AUTO_INCREMENT锁定模式

本节介绍 AUTO_INCREMENT 用于生成自动增量值 锁定模式 的行为 ,以及每种锁定模式如何影响复制。 使用 innodb_autoinc_lock_mode 配置参数 在启动时配置自动增量锁定模式

以下术语用于描述 innodb_autoinc_lock_mode 设置:

  • INSERT 似的 陈述

    在表中生成新的行中的所有语句,包括 INSERT INSERT ... SELECT REPLACE REPLACE ... SELECT ,和 LOAD DATA 包括 简单插入 批量插入 混合模式 插入。

  • 简单插入

    可以预先确定要插入的行数的语句(最初处理语句时)。 这包括单行和多行 INSERT 以及 REPLACE 没有嵌套子查询的语句,但不包括 INSERT ... ON DUPLICATE KEY UPDATE

  • 批量插入

    预先不知道要插入的行数(以及所需的自动增量值的数量)的语句。 这包括 INSERT ... SELECT REPLACE ... SELECT LOAD DATA 声明,但不是简单的 INSERT 在处理每一行时,一次为列 InnoDB 分配新值 AUTO_INCREMENT

  • 混合模式插入

    这些是 简单插入 语句,它指定一些(但不是全部)新行的自动增量值。 下面 c1 是一个 示例,其中 是一 AUTO_INCREMENT 列表 t1

    INSERT INTO t1(c1,c2)VALUES(1,'a'),(NULL,'b'),(5,'c'),(NULL,'d');
    

    另一种类型的 混合模式插入 INSERT ... ON DUPLICATE KEY UPDATE ,在最坏的情况下实际上是 INSERT 后跟a UPDATE ,其中 AUTO_INCREMENT 在更新阶段期间可以使用或不使用列 的分配值

innodb_autoinc_lock_mode 配置参数 有三种可能的设置 对于 传统 连续 交错 锁定模式, 设置分别为0,1或2 从MySQL 8.0开始,交错锁定模式( innodb_autoinc_lock_mode=2 )是默认设置。 在MySQL 8.0之前,连续锁定模式是默认值( innodb_autoinc_lock_mode=1 )。

MySQL 8.0中的交错锁定模式的默认设置反映了从基于语句的复制到基于行的复制的更改,作为默认复制类型。 基于语句的复制需要连续的自动增量锁定模式,以确保为给定的SQL语句序列以可预测和可重复的顺序分配自动增量值,而基于行的复制对SQL语句的执行顺序不敏感。

  • innodb_autoinc_lock_mode = 0 传统 锁定模式)

    传统的锁定模式提供了与 innodb_autoinc_lock_mode MySQL 5.1中引入配置参数 之前相同的行为 传统的锁定模式选项用于向后兼容,性能测试以及解决“混合模式插入”问题,因为语义可能存在差异。

    在此锁定模式下,所有 INSERT-like 语句都会获得一个特殊的表级 AUTO-INC 锁,以便插入带有 AUTO_INCREMENT 列的表中。 此锁通常保持在语句的末尾(而不是事务的结尾),以确保为给定的 INSERT 语句 序列以可预测和可重复的顺序分配自动增量值 ,并确保自动增量值由任何给定的声明分配是连续的。

    对于基于语句的复制,这意味着在从属服务器上复制SQL语句时,自动增量列使用的值与主服务器上的值相同。 执行多个 INSERT 语句 的结果 是确定性的,并且从站再现与主站上相同的数据。 如果多个 INSERT 语句 生成的自动递增值 是交错的,则两个并发 INSERT 语句 的结果 将是不确定的,并且无法使用基于语句的复制可靠地传播到从属服务器。

    为清楚起见,请考虑使用此表的示例:

    CREATE TABLE t1(
      c1 INT(11)NOT NULL AUTO_INCREMENT,
      c2 VARCHAR(10)DEFAULT NULL,
      主要关键(c1)
    )ENGINE = InnoDB;
    

    假设有两个事务正在运行,每个事务都将行插入带有 AUTO_INCREMENT 的表中 一个事务使用 INSERT ... SELECT 插入1000行 语句, 另一个事务使用 插入一行的简单 INSERT 语句:

    Tx1:INSERT INTO t1(c2)从另一个表中选择1000行...
    Tx2:INSERT INTO t1(c2)VALUES('xxx');
    

    InnoDB 事先无法判断从 Tx1 SELECT 中的 INSERT 语句中 检索了多少行 ,并且 随着 语句的进行,它会一次分配一个自动增量值。 使用保持在语句末尾的表级锁定,一次只能 执行 一个 INSERT 引用表的语句 t1 ,并且不会交错生成不同语句的自动增量数。 由Tx1 INSERT ... SELECT 语句 生成的自动递增值 是连续的,并且由(单个)自动递增值使用 INSERT Tx2中的语句要小于或大于用于Tx1的语句,具体取决于首先执行的语句。

    只要SQL语句在从二进制日志重放时(在使用基于语句的复制时或在恢复方案中)以相同的顺序执行,结果与首次运行Tx1和Tx2时的结果相同。 因此,表级锁定一直持续到语句结束时, INSERT 使用自动增量安全 的语句可以 安全地用于基于语句的复制。 但是,当多个事务同时执行insert语句时,这些表级锁限制了并发性和可伸缩性。

    在前面的示例中,如果没有表级锁定,则用于 INSERT Tx2 中的自动增量列的值 取决于语句执行的时间。 如果 INSERT Tx2在 INSERT Tx1运行时执行(而不是在启动之前或完成之后),则由两个 INSERT 语句 分配的特定自动增量值 是不确定的,并且可能因运行而异。

    连续 锁定模式下, InnoDB 可以避免将表级 AUTO-INC 锁定用于 预先知道行数的 简单插入 语句,并且仍然保留基于语句的复制的确定性执行和安全性。

    如果您不使用二进制日志作为恢复或复制的一部分重放SQL语句,则 交错 锁定模式可用于消除表级 AUTO-INC 锁的 所有使用,从而 实现更高的并发性和性能,但代价是允许自动存在空白 - 由语句分配的增量编号,可能具有由并发执行的语句交错分配的编号。

  • innodb_autoinc_lock_mode = 1 连续 锁定模式)

    在此模式下, 批量插入 使用特殊的 AUTO-INC 表级锁定并保持它直到语句结束。 这适用于所有 INSERT ... SELECT REPLACE ... SELECT LOAD DATA 语句。 只有一个持有 AUTO-INC 锁的 语句 可以一次执行。 如果批量插入操作的源表与目标表不同,则 AUTO-INC 在从源表中选择的第一行上执行共享锁之后,将对目标表执行锁定。 如果批量插入操作的源和目标是同一个表,则 AUTO-INC 在对所有选定的行执行共享锁定后执行锁定。

    简单插入 (预先知道要插入的行数) AUTO-INC 通过在互斥锁(轻量级锁定)的控制下获得所需数量的自动增量值来 避免表级 锁定在分配过程的持续时间内保持, 直到语句完成。 AUTO-INC 除非 AUTO-INC 另一个事务持有 锁,否则 不使用表级 如果另一个事务持有 AUTO-INC 锁,则 简单插入 等待 AUTO-INC 锁定,就像它是 批量插入

    此锁定模式确保在存在 INSERT 未提前知道行数 语句(以及在语句进行时指定自动增量编号)的情况下,由任何 INSERT -like 语句 指定的所有自动增量值 都是连续,并且操作对于基于语句的复制是安全的。

    简而言之,这种锁定模式显着提高了可伸缩性,同时可以安全地使用基于语句的复制。 此外,与 传统 锁定模式一样,由任何给定语句分配的自动递增数字是 连续的 没有变化 在语义比较 传统 对于使用自动递增,有一个重要的例外,任何声明模式。

    混合模式插入 的例外情况是, 用户为 AUTO_INCREMENT 多行 简单插入 ”中的 某些行(但不是所有行) 提供 列的 显式值 对于此类插入,请 InnoDB 分配比要插入的行数更多的自动增量值。 但是,自动分配的所有值都是连续生成(因此高于)最近执行的先前语句生成的自动增量值。 超额 号码丢失了。

  • innodb_autoinc_lock_mode = 2 交错 锁定模式)

    在此锁定模式下,没有 INSERT -like 语句使用表级 AUTO-INC 锁,并且多个语句可以同时执行。 这是最快且最具扩展性的锁定模式,但 在从二进制日志重放SQL语句时使用基于语句的复制或恢复方案时 ,这是 不安全的

    在这种锁定模式下,自动增量值保证是唯一的,并且在所有同时执行的 INSERT 类似 语句中 单调递增 但是,因为多个语句可以同时生成数字(即,数字的分配 在语句之间 交错 ),所以为任何给定语句插入的行生成的值可能不是连续的。

    如果执行的唯一语句是 简单插入 ,其中要插入的行数是提前知道的,则除了 混合模式插入 之外,单个语句生成的数字没有间隙 但是,当 执行 批量插入 ,任何给定语句分配的自动增量值可能存在间隙。

InnoDB AUTO_INCREMENT锁定模式使用含义
  • 使用复制自动增量

    如果使用基于语句的复制,请设置 innodb_autoinc_lock_mode 为0或1,并在主服务器及其从服务器上使用相同的值。 如果使用 innodb_autoinc_lock_mode = 2( 交错 )或主站和从站不使用相同锁定模式的配置, 则不确保从站上的自动增量值 与主站上的相同。

    如果使用基于行或混合格式的复制,则所有自动增量锁定模式都是安全的,因为基于行的复制对SQL语句的执行顺序不敏感(并且混合格式使用基于行的方式)复制任何对基于语句的复制不安全的语句。

  • 丢失 自动递增值和序列间隙

    在所有锁定模式(0,1和2)中,如果生成自动增量值的事务回滚,则这些自动增量值将 丢失 一旦为自动增量列生成了值,就无法回滚它,无论 INSERT -like 语句是否完成,以及是否回滚包含的事务。 这些丢失的值不会被重用。 因此,存储在 AUTO_INCREMENT 中的值可能存在间隙

  • AUTO_INCREMENT 指定NULL或0

    在所有的锁模式(0,1,2),如果用户指定NULL或0用于 AUTO_INCREMENT 在列 INSERT InnoDB 将行仿佛没有指定值,并且生成用于它的新值。

  • AUTO_INCREMENT 指定负值

    在所有锁定模式(0,1和2)中,如果为 AUTO_INCREMENT 指定负值,则不会定义自动增量机制的行为

  • 如果该 AUTO_INCREMENT 值大于指定整数类型的最大整数

    在所有锁定模式(0,1和2)中,如果值大于可以存储在指定整数类型中的最大整数,则不会定义自动增量机制的行为。

  • 批量插入 ”的 自动增量值的差距

    innodb_autoinc_lock_mode 设定为0( 传统 )或1( 连续 ),通过任何给定语句生成的自动递增的值是连续的,没有间隙,这是因为表级 AUTO-INC 锁一直保持到该语句的末尾,只有一个这样的语句可以一次执行。

    innodb_autoinc_lock_mode 设置为2( 交织 ),有可能是在所产生的自动递增值间隙 批量插入 , ” 但只有当有同时执行的 INSERT 的语句。

    对于锁定模式1或2,在连续语句之间可能出现间隙,因为对于批量插入,可能不知道每个语句所需的确切数量的自动增量值,并且可能过高估计。

  • 混合模式插入 指定的自动递增值

    考虑 混合模式插入 ,其中 简单插入 指定某些(但不是全部)结果行的自动增量值。 这种语句在锁定模式0,1和2中表现不同。例如,假设 c1 是一 AUTO_INCREMENT 列表 t1 ,并且最近自动生成的序列号是100。

    mysql> CREATE TABLE t1 (
        - > c1 INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 
        - > c2 CHAR(1)
        - >) ENGINE = INNODB;
    

    现在,考虑以下 混合模式插入 语句:

    MySQL的> INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (5,'c'), (NULL,'d');
    

    随着 innodb_autoinc_lock_mode 设置为0( 传统 ),这四个新的行是:

    MySQL的> SELECT c1, c2 FROM t1 ORDER BY c2;
    + ----- + ------ +
    | c1 | c2 |
    + ----- + ------ +
    | 1 | a |
    | 101 | b |
    | 5 | c |
    | 102 | d |
    + ----- + ------ +
    

    下一个可用的自动增量值为103,因为自动增量值一次分配一个,而不是在语句执行开始时一次分配。 无论是否同时执行 INSERT -like 语句(任何类型), 此结果都是正确的

    随着 innodb_autoinc_lock_mode 设置为1( 连续 ),这四个新行也:

    MySQL的> SELECT c1, c2 FROM t1 ORDER BY c2;
    + ----- + ------ +
    | c1 | c2 |
    + ----- + ------ +
    | 1 | a |
    | 101 | b |
    | 5 | c |
    | 102 | d |
    + ----- + ------ +
    

    但是,在这种情况下,下一个可用的自动增量值是105,而不是103,因为在处理语句时分配了四个自动增量值,但只使用了两个。 无论是否同时执行 INSERT -like 语句(任何类型), 此结果都是正确的

    innodb_autoinc_lock_mode 设定为模式2( 交织 ),四个新的行是:

    MySQL的> SELECT c1, c2 FROM t1 ORDER BY c2;
    + ----- + ------ +
    | c1 | c2 |
    + ----- + ------ +
    | 1 | a |
    |   x| b |
    | 5 | c |
    |   y| d |
    + ----- + ------ +
    

    的值 x y 是独一无二的,比任何先前产生的行大。 然而,具体的数值 x ,并 y 依赖于并行执行语句生成自动递增值的数量。

    最后,考虑以下语句,在最近生成的序列号为100时发出:

    MySQL的> INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (101,'c'), (NULL,'d');
    

    对于任何 innodb_autoinc_lock_mode 设置,此语句将生成重复键错误23000( Can't write; duplicate key in table ),因为为行分配了101并且行的 (NULL, 'b') 插入 (101, 'c') 失败。

  • AUTO_INCREMENT 在一系列 INSERT 语句 的中间 修改 列值

    在MySQL 5.7及更早版本中,修改 语句 AUTO_INCREMENT 序列中间 列值 INSERT 可能会导致 重复条目 错误。 例如,如果执行的 UPDATE 操作将 AUTO_INCREMENT 列值 更改为 大于当前最大自动增量值的值,则 INSERT 未指定未使用的自动增量值的 后续 操作可能会遇到 重复条目 错误。 在MySQL 8.0及更高版本中,如果您修改了 AUTO_INCREMENT 如果列值大于当前最大自动增量值,则新值将保持不变,后续 INSERT 操作将从新的较大值开始分配自动增量值。 以下示例演示了此行为。

    mysql> CREATE TABLE t1 (
        - > c1 INT NOT NULL AUTO_INCREMENT,
        - > PRIMARY KEY (c1)
        - >  ) ENGINE = InnoDB;
    
    MySQL的> INSERT INTO t1 VALUES(0), (0), (3);
    
    MySQL的> SELECT c1 FROM t1;
    + ---- +
    | c1 |
    + ---- +
    | 1 |
    | 2 |
    | 3 |
    + ---- +
    
    MySQL的> UPDATE t1 SET c1 = 4 WHERE c1 = 1;
    
    MySQL的> SELECT c1 FROM t1;
    + ---- +
    | c1 |
    + ---- +
    | 2 |
    | 3 |
    | 4 |
    + ---- +
    
    MySQL的> INSERT INTO t1 VALUES(0);
    
    MySQL的> SELECT c1 FROM t1;
    + ---- +
    | c1 |
    + ---- +
    | 2 |
    | 3 |
    | 4 |
    | 5 |
    + ---- + 
    
InnoDB AUTO_INCREMENT计数器初始化

本节介绍如何 InnoDB 初始化 AUTO_INCREMENT 计数器。

如果 AUTO_INCREMENT InnoDB 指定 ,则内存中表对象包含一个称为自动增量计数器的特殊计数器,该计数器在为列分配新值时使用。

在MySQL 5.7及更早版本中,自动增量计数器仅存储在主存储器中,而不存储在磁盘上。 要在服务器重新启动后初始化自动增量计数器, InnoDB 将在第一次插入到包含 AUTO_INCREMENT 的表中执行以下语句的等效语句

SELECT MAX(ai_col)FROM table_nameFOR UPDATE;

在MySQL 8.0中,此行为已更改。 每次更改时,当前最大自动增量计数器值将写入重做日志,并保存到每个检查点上的引擎专用系统表中。 这些更改使当前最大自动增量计数器值在服务器重新启动时保持不变。

在正常关闭后重新启动服务器上, InnoDB 使用存储在数据字典系统表中的当前最大自动增量值初始化内存中自动递增计数器。

在崩溃恢复期间在服务器上重新启动时, InnoDB 使用存储在数据字典系统表中的当前最大自动增量值初始化内存中自动增量计数器,并扫描重做日志以查找自上一个检查点以来写入的自动增量计数器值。 如果重做日志值大于内存中计数器值,则应用重做日志值。 但是,在服务器崩溃的情况下,无法保证重用先前分配的自动增量值。 每次由于 INSERT 更改当前最大自动增量值 UPDATE 操作时,新值将写入重做日志,但如果在重做日志刷新到磁盘之前发生崩溃,则在重新启动服务器后初始化自动增量计数器时,可以重用先前分配的值。

在MySQL 8.0及更高版本中 InnoDB 使用等效 语句来初始化自动增量计数器 的唯一情况 是在 导入 没有 元数据文件 的表空间 否则,从 元数据文件中 读取当前最大自动增量计数器值 SELECT MAX(ai_col) FROM table_name FOR UPDATE .cfg .cfg

在MySQL 5.7及更早版本中,服务器重新启动会取消 AUTO_INCREMENT = N table选项 的效果,该 选项可以在 CREATE TABLE or ALTER TABLE 语句中用于设置初始计数器值或分别更改现有计数器值。 在MySQL 8.0中,服务器重新启动不会取消 AUTO_INCREMENT = N 表选项 的效果 如果将自动递增计数器初始化为特定值,或者将自动递增计数器值更改为更大的值,则新值将在服务器重新启动时保持不变。

注意

ALTER TABLE ... AUTO_INCREMENT = N 只能将自动增量计数器值更改为大于当前最大值的值。

在MySQL 5.7及更早版本中,服务器在 ROLLBACK 操作后 立即重新启动 可能会导致重用先前分配给回滚事务的自动增量值,从而有效地回滚当前的最大自动增量值。 在MySQL 8.0中,当前的最大自动增量值是持久的,从而阻止了以前分配的值的重用。

如果 SHOW TABLE STATUS 语句在初始化自动增量计数器之前检查表,则 InnoDB 打开表并使用存储在数据字典系统表中的当前最大自动增量值初始化计数器值。 该值存储在内存中以供以后插入或更新使用。 计数器值的初始化使用表上的常规异或锁定读取,该读取持续到事务结束。 InnoDB 在为具有用户指定的自动增量值大于0的新创建的表初始化自动增量计数器时,遵循相同的过程。

初始化自动递增计数器后,如果在插入行时未显式指定自动递增值,则 InnoDB 隐式递增计数器并将新值分配给列。 如果插入显式指定自动增量列值的行,并且该值大于当前最大计数器值,则计数器将设置为指定值。

InnoDB 只要服务器运行,就使用内存中的自动增量计数器。 停止并重新启动服务器时, InnoDB 重新初始化自动增量计数器,如前所述。

auto_increment_offset 配置选项确定为起点 AUTO_INCREMENT 列值。 默认设置为1。

auto_increment_increment 配置选项控制连续列的值之间的间隔。 默认设置为1。

15.6.1.5 InnoDB和FOREIGN KEY约束

InnoDB 本节中的以下主题描述 存储引擎 如何 处理外键约束:

有关外键使用信息和示例,请参见 第13.1.20.6节“使用FOREIGN KEY约束”

外键定义

InnoDB 表的 外键定义符合 以下条件:

  • InnoDB 允许外键引用任何索引列或列组。 但是,在引用的表中,必须有一个索引,其中引用的列是 同一顺序 中的 第一 列。 InnoDB 还会考虑添加到索引的 隐藏列 (请参见 第15.6.2.1节“聚簇和二级索引” )。

  • InnoDB 当前不支持具有用户定义分区的表的外键。 这意味着没有用户分区的 InnoDB 表可能包含外键引用的外键引用或列。

  • InnoDB 允许外键约束引用非唯一键。 这是 InnoDB 标准SQL 扩展。

参考行动

InnoDB 表的 外键的引用操作 受以下条件限制:

  • 虽然 SET DEFAULT MySQL服务器允许,但它被拒绝为无效 InnoDB CREATE TABLE ALTER TABLE 利用这一条款语句不得用于InnoDB表。

  • 如果父表中有多个行具有相同的引用键值,则 InnoDB 在外键检查中执行操作,就好像其他具有相同键值的父行不存在一样。 例如,如果已定义 RESTRICT 类型约束,并且存在具有多个父行的子行, InnoDB 则不允许删除任何这些父行。

  • InnoDB 基于对应于外键约束的索引中的记录,通过深度优先算法执行级联操作。

  • 如果 ON UPDATE CASCADE 或者 ON UPDATE SET NULL recurses更新 它在级联期间先前已 更新的 同一个表 ,它的作用就像 RESTRICT 这意味着您不能使用自引用 ON UPDATE CASCADE ON UPDATE SET NULL 操作。 这是为了防止级联更新导致的无限循环。 自引用的 ON DELETE SET NULL ,在另一方面,是可能的,因为是自引用 ON DELETE CASCADE 级联操作可能不会嵌套超过15级。

  • 与MySQL一样,在一个SQL语句中, 逐行 插入,删除或更新许多行, InnoDB 检查 UNIQUE FOREIGN KEY 约束。 执行外键检查时, InnoDB 在必须查看的子记录或父记录上设置共享行级锁。 InnoDB 立即检查外键约束; 检查不会延迟到事务提交。 根据SQL标准,默认行为应该是延迟检查。 也就是说,只有在处理 完整个SQL语句 后才会检查约束 直到 InnoDB 实现延迟约束检查,有些事情是不可能的,例如删除使用外键引用自身的记录。

生成列和虚拟索引的外键限制
  • 在存储生成列外键约束不能使用 CASCADE SET NULL SET DEFAULT 作为 ON UPDATE 参照动作,也不能使用 SET NULL SET DEFAULT 作为 ON DELETE 参照动作。

  • 在存储生成列的基本列外键约束不能使用 CASCADE SET NULL SET DEFAULT 作为 ON UPDATE ON DELETE 引用操作。

  • 外键约束不能引用 虚拟生成的列

  • 在MySQL 8.0之前,外键约束不能引用在虚拟生成列上定义的辅助索引。

15.6.1.6 InnoDB表的限制

InnoDB 表中的 限制 在本节的以下主题中描述:

警告

在使用NFS之前 InnoDB ,请查看 使用NFS与MySQL中 概述的潜在问题

最大值和最小值
  • 一个表最多可包含1017列。 虚拟生成列包含在此限制中。

  • 一个表最多可包含64个 二级索引

  • 对于 InnoDB 使用 DYNAMIC COMPRESSED 行格式的 表, 索引键前缀长度限制为3072字节

    对于 InnoDB 使用 REDUNDANT COMPACT 行格式的 表, 索引键前缀长度限制为767字节 例如,您可能会 在一个 或一 上使用超过191个字符 列前缀 索引 达到此限制 ,假定 为每个字符设置 一个 字符集且最多为4个字节。 TEXT VARCHAR utf8mb4

    尝试使用超出限制的索引键前缀长度会返回错误。

    适用于索引键前缀的限制也适用于全列索引键。

  • 如果 通过 在创建MySQL实例时 指定 选项 InnoDB 页面大小减小 到8KB或4KB innodb_page_size ,则索引键的最大长度将按比例降低,基于16KB页面大小的3072字节限制。 也就是说,当页面大小为8KB时,最大索引密钥长度为1536字节,当页面大小为4KB时,最大索引密钥长度为768字节。

  • 多列索引最多允许16列。 超过限制会返回错误。

    ERROR 1070(42000):指定的关键部件太多; 最多允许16件
    
  • 最大行长度,除了可变长度列( VARBINARY VARCHAR BLOB TEXT ),是比对于4KB,8KB,16KB,32KB和页大小的页的一半稍少。 例如,默认 innodb_page_size 值为16KB 的最大行长度 约为8000字节。 对于 InnoDB 64KB 页面大小,最大行长度约为16000字节。 LONGBLOB LONGTEXT 列必须小于4GB,并且总行长度(包括 BLOB TEXT 列)必须小于4GB。

    如果一行长度小于半页,则所有行都存储在页面内。 如果它超过半页,则选择可变长度列用于外部页外存储,直到该行适合半页,如 第15.11.2节“文件空间管理”中所述

  • 虽然 InnoDB 内部支持的行大小超过65,535字节,但MySQL本身对所有列的总大小强加了行大小限制为65,535:

    mysql> CREATE TABLE t (a VARCHAR(8000), b VARCHAR(10000),
        - > c VARCHAR(10000), d VARCHAR(10000), e VARCHAR(10000),
        - >f VARCHAR(10000), g VARCHAR(10000)) ENGINE=InnoDB;
    ERROR 1118(42000):行大小太大。最大行大小
    使用的表类型,不计算BLOB,是65535.你必须改变一些
    列到TEXT或BLOB
    

    请参见 第C.10.4节“表列数和行大小的限制”

  • 在某些较旧的操作系统上,文件必须小于2GB。 这不是 InnoDB 自身 的限制 ,但如果您需要大型表空间,请使用几个较小的数据文件而不是一个大型数据文件进行配置。

  • InnoDB 日志文件 的总大小 最大可达512GB。

  • 最小表空间大小略大于10MB。 最大表空间大小取决于 InnoDB 页面大小。

    表15.3 InnoDB最大表空间大小

    InnoDB页面大小 最大表空间大小
    4KB 16TB
    8KB 32TB
    16KB 64TB
    32KB 128TB
    64KB 256TB

    最大表空间大小也是表的最大大小。

  • 表空间文件的路径(包括文件名)不能超过 MAX_PATH Windows上 限制。 在Windows 10之前, MAX_PATH 限制为260个字符。 从Windows 10版本1607开始, MAX_PATH 从常见的Win32文件和目录函数中删除了限制,但您必须启用新行为。

  • 默认页面大小 InnoDB 为16KB。 您可以通过 innodb_page_size 在创建MySQL实例时 配置 选项 来增加或减少页面大小

    支持32KB和64KB页面大小,但 ROW_FORMAT=COMPRESSED 不支持大于16KB的页面大小。 对于32KB和64KB页面大小,最大记录大小为16KB。 对于 innodb_page_size=32KB ,范围大小为2MB。 对于 innodb_page_size=64KB ,范围大小是4MB。

    使用特定 InnoDB 页面大小的 MySQL实例 无法使用来自使用不同页面大小的实例的数据文件或日志文件。

InnoDB表的限制
  • ANALYZE TABLE 通过 对每个索引树 执行 随机潜水 并相应地更新索引基数估计 来确定索引基数(显示在 输出 Cardinality 列中 SHOW INDEX 因为这些只是估计,所以重复运行 会产生不同的数字。 这使得 表格 快速 但不是100%准确,因为它不会考虑所有行。 ANALYZE TABLE ANALYZE TABLE InnoDB

    通过打开 配置选项, 您可以 更精确,更稳定地 收集 统计信息 ,如 第15.8.10.1节“配置持久优化器统计信息参数”中所述 启用该设置 后,在对索引列数据进行重大更改后 运行非常重要 ,因为不会定期重新计算统计信息(例如在服务器重新启动后)。 ANALYZE TABLE innodb_stats_persistent ANALYZE TABLE

    如果启用了持久性统计设置,则可以通过修改 innodb_stats_persistent_sample_pages 系统变量 来更改随机潜水次数 如果禁用持久统计信息设置,请 innodb_stats_transient_sample_pages 改为 修改 系统变量。

    MySQL在连接优化中使用索引基数估计。 如果未以正确的方式优化连接,请尝试使用 ANALYZE TABLE 在少数几个 ANALYZE TABLE 不能为您的特定表生成足够好的值的 情况下 ,您可以使用 FORCE INDEX 查询来强制使用特定索引,或者设置 max_seeks_for_key 系统变量以确保MySQL更喜欢对表扫描进行索引查找。 请参见 第B.4.5节“与优化程序相关的问题”

  • 如果语句或事务在表上运行,并且 ANALYZE TABLE 在同 一个表 上运行,然后执行第二个 ANALYZE TABLE 操作,则第二个 ANALYZE TABLE 操作将被阻止,直到语句或事务完成为止。 出现此问题的原因 ANALYZE TABLE ANALYZE TABLE 完成运行 时将当前加载的表定义标记为已过时 新的陈述或交易(包括第二次 ANALYZE TABLE 必须将新表定义加载到表缓存中,直到当前运行的语句或事务完成并清除旧表定义时才会发生这种情况。 不支持加载多个并发表定义。

  • SHOW TABLE STATUS InnoDB 除了表保留的物理大小之外, 没有给出 表的 准确统计信息 行计数只是SQL优化中使用的粗略估计。

  • InnoDB 不保留表中的内部行数,因为并发事务可能同时 看到 不同数量的行。 因此, SELECT COUNT(*) 语句只计算当前事务可见的行。

    有关信息如何 InnoDB 处理 SELECT COUNT(*) 报表,请参阅 COUNT() 说明在 第12.20.1,“集合(GROUP BY)功能说明”

  • 在Windows上, InnoDB 始终以小写形式在内部存储数据库和表名。 要以二进制格式将数据库从Unix移动到Windows或从Windows移动到Unix,请使用小写名称创建所有数据库和表。

  • AUTO_INCREMENT ai_col 必须被定义为一个指数,使得它能够进行一个索引的等效的部分 上的表查找以获得最大列值。 通常,这是通过使列成为某些表索引的第一列来实现的。 SELECT MAX(ai_col)

  • InnoDB AUTO_INCREMENT 在初始化 AUTO_INCREMENT 表上的 先前指定的 列时,在 关联的索引的末尾设置独占锁

    使用 innodb_autoinc_lock_mode=0 InnoDB 使用特殊的 AUTO-INC 表锁定模式,其中获取锁定并在访问自动增量计数器时保持到当前SQL语句的末尾。 在保持 AUTO-INC 表锁定 时,其他客户端无法插入表中 对于发生相同的行为 批量插入 innodb_autoinc_lock_mode=1 表级 AUTO-INC 锁不用于 innodb_autoinc_lock_mode=2 有关更多信息,请参见 第15.6.1.4节“InnoDB中的AUTO_INCREMENT处理”

  • AUTO_INCREMENT 整数列用完值时,后续 INSERT 操作将返回重复键错误。 这是一般的MySQL行为。

  • DELETE FROM tbl_name 不会重新生成表,而是逐个删除所有行。

  • 级联外键操作不会激活触发器。

  • 不能创建与内部的名称匹配的列名的表 InnoDB 列(其中包括 DB_ROW_ID DB_TRX_ID DB_ROLL_PTR ,和 DB_MIX_ID )。 此限制适用于在任何字母大小写中使用名称。

    MySQL的> CREATE TABLE t1 (c1 INT, db_row_id INT) ENGINE=INNODB;
    错误1166(42000):错误的列名'db_row_id'
    
锁定和交易
  • LOCK TABLES 如果 innodb_table_locks=1 (默认值), 则在每个表上获取两个锁 除了MySQL层上的表锁之外,它还获取 InnoDB 表锁。 4.1.2之前的MySQL版本没有获取 InnoDB 表锁; 可以通过设置选择旧行为 innodb_table_locks=0 如果未 InnoDB 获取表锁, LOCK TABLES 即使某些表的记录被其他事务锁定 也会完成。

    在MySQL 8.0中, innodb_table_locks=0 对于显式锁定的表没有任何影响 LOCK TABLES ... WRITE 它对通过 LOCK TABLES ... WRITE 隐式(例如,通过触发器)或通过隐藏(例如,通过触发器) 锁定读取或写入的表有效 LOCK TABLES ... READ

  • InnoDB 事务提交或中止时,将释放事务持有的 所有 锁。 因此,它并没有多大意义,调用 LOCK TABLES InnoDB 表中 autocommit=1 模式,因为所获得的 InnoDB 表锁将被立即释放。

  • 您无法在事务中锁定其他表,因为 LOCK TABLES 执行隐式 COMMIT UNLOCK TABLES

  • 有关与并发读写事务关联的限制,请参见 第15.6.6节“撤消日志”

15.6.2索引

本节介绍与 InnoDB 索引 相关的主题

15.6.2.1集群和二级索引

每个 InnoDB 表都有一个称为 聚簇索引 的特殊索引, 其中存储了行的数据。 通常,聚簇索引与 主键 同义 要从查询,插入和其他数据库操作中获得最佳性能,您必须了解如何 InnoDB 使用聚簇索引来优化每个表的最常见查找和DML操作。

  • PRIMARY KEY 表上 定义a 时, InnoDB 将其用作聚簇索引。 为您创建的每个表定义主键。 如果没有逻辑唯一且非空列或列集,请添加一个新的 自动增量 列,其值将自动填充。

  • 如果没有 PRIMARY KEY 为表 定义一个 ,MySQL将找到 UNIQUE 所有键列 所在的第一个 索引, NOT NULL 并将 InnoDB 其用作聚簇索引。

  • 如果表没有 PRIMARY KEY 没有 合适的 UNIQUE 索引,则在 InnoDB 内部生成一个隐藏的聚簇索引 GEN_CLUST_INDEX ,该 索引 在包含行ID值的合成列上 命名 行按照 InnoDB 分配给此类表中的行 的ID排序 行ID是一个6字节的字段,随着新行的插入而单调增加。 因此,由行ID排序的行在物理上处于插入顺序。

聚簇索引如何加快查询速度

通过聚簇索引访问行很快,因为索引搜索直接指向包含所有行数据的页面。 如果表很大,与使用与索引记录不同的页面存储行数据的存储组织相比,聚簇索引体系结构通常会保存磁盘I / O操作。

二级指数如何与聚集指数相关联

除聚簇索引之外的所有索引都称为 辅助索引 InnoDB ,辅助索引中的每个记录都包含该行的主键列,以及为二级索引指定的列。 InnoDB 使用此主键值来搜索聚簇索引中的行。

如果主键很长,则二级索引使用更多空间,因此使用短主键是有利的。

有关利用 InnoDB 聚簇索引和二级索引的 准则 ,请参见 第8.3节“优化和索引”

15.6.2.2 InnoDB索引的物理结构

除空间索引外, InnoDB 索引是 B树 数据结构。 空间索引使用 R树 R树 是用于索引多维数据的专用数据结构。 索引记录存储在其B树或R树数据结构的叶页中。 索引页的默认大小为16KB。

将新记录插入 InnoDB 聚簇索引时 InnoDB 尝试将页面的1/16保留为可用,以便将来插入和更新索引记录。 如果索引记录按顺序(升序或降序)插入,则生成的索引页大约为15/16。 如果以随机顺序插入记录,则页面从1/2到15/16满。

InnoDB 在创建或重建B树索引时执行批量加载。 这种索引创建方法称为排序索引构建。 innodb_fill_factor 配置选项定义的空间作为排序指标构建过程中填充,为今后指数增长预留的剩余空间每个B树页的百分比。 空间索引不支持排序索引构建。 有关更多信息,请参见 第15.6.2.3节“排序索引构建” 一个 innodb_fill_factor 100设置叶免费为未来指数增长的聚簇索引页的空间的1/16。

如果 InnoDB 索引页 的填充因子 低于 MERGE_THRESHOLD 默认值(如果未指定则为50%),则 InnoDB 尝试收缩索引树以释放页面。 MERGE_THRESHOLD 设置适用于B树和R树索引。 有关更多信息,请参见 第15.8.11节“配置索引页的合并阈值”

您可以 通过 在初始化MySQL实例之前 设置 配置选项 来定义 MySQL实例中 所有 表空间 页面大小 定义实例的页面大小后,如果不重新初始化实例,则无法更改它。 支持的大小为64KB,32KB,16KB(默认),8KB和4KB。 InnoDB innodb_page_size

使用特定 InnoDB 页面大小的 MySQL实例 无法使用来自使用不同页面大小的实例的数据文件或日志文件。

15.6.2.3排序索引构建

InnoDB 在创建或重建索引时,执行批量加载而不是一次插入一个索引记录。 这种索引创建方法也称为排序索引构建。 空间索引不支持排序索引构建。

索引构建有三个阶段。 在第一阶段, 扫描 聚簇索引 ,生成索引条目并将其添加到排序缓冲区。 排序缓冲区 变满时,条目将被排序并写入临时中间文件。 此过程也称为 运行 在第二阶段,将一个或多个运行写入临时中间文件,对文件中的所有条目执行合并排序。 在第三个也是最后一个阶段,已排序的条目将插入到 B树中

在引入排序索引构建之前,使用插入API一次将索引条目插入到B树中一条记录。 此方法涉及打开B树 游标 以查找插入位置,然后使用 乐观 插入 将条目插入B树页面 如果由于页面已满而导致插入失败, 则将执行 悲观 插入,这涉及打开B树游标并根据需要拆分和合并B树节点以查找条目的空间。 这种 自上而下 的弊端 构建索引的方法是搜索插入位置的成本以及B树节点的常量拆分和合并。

排序索引构建使用 自下而上 构建索引的方法。 使用这种方法,对最右侧叶页的引用保存在B树的所有级别。 分配必要B树深度的最右侧叶页,并根据其排序顺序插入条目。 一旦叶子页面已满,节点指针将附加到父页面,并为下一个插入分配一个兄弟叶页面。 此过程将继续,直到插入所有条目,这可能导致插入到根级别。 分配兄弟页面时,将释放对先前固定的叶子页面的引用,并且新分配的叶子页面将成为最右侧的叶子页面和新的默认插入位置。

为未来指数增长保留B树页面空间

要为将来的索引增长留出空间,可以使用 innodb_fill_factor 配置选项保留B树页面空间的百分比。 例如, innodb_fill_factor 在排序索引构建期间 ,设置 为80可保留B树页面中20%的空间。 此设置适用于B树叶和非叶页。 它不适用于用于 TEXT BLOB 输入的 外部页面 保留的空间量可能与配置的不完全相同,因为该 innodb_fill_factor 值被解释为提示而不是硬限制。

排序索引构建和全文索引支持

全文索引 支持排序索引构建 以前,SQL用于将条目插入到全文索引中。

排序索引构建和压缩表

对于 压缩表 ,先前的索引创建方法将条目附加到压缩和未压缩页面。 当修改日志(表示压缩页面上的可用空间)变满时,压缩页面将被重新压缩。 如果由于空间不足而导致压缩失败,则页面将被拆分。 对于已排序的索引构建,条目仅附加到未压缩的页面。 当未压缩的页面变满时,它将被压缩。 自适应填充用于确保在大多数情况下压缩成功,但如果压缩失败,则会拆分页面并再次尝试压缩。 此过程将继续,直到压缩成功。 有关压缩B-Tree页面的更多信息,请参阅 第15.9.1.5节“压缩如何用于InnoDB表”

排序索引构建和重做日志记录

在排序的索引构建期间禁用 重做日志记录 相反,有一个 检查点 可确保索引构建能够承受崩溃或故障。 检查点强制将所有脏页写入磁盘。 在排序索引构建期间, 定期发信号通知 页面清理器 线程以刷新 脏页面 以确保可以快速处理检查点操作。 通常,当清洁页面的数量低于设定阈值时,页面清理器线程会刷新脏页面。 对于排序索引构建,会立即刷新脏页以减少检查点开销并并行化I / O和CPU活动。

排序索引构建和优化程序统计信息

排序索引构建可能导致 优化程序 统计信息与以前的索引创建方法生成的统计信息不同。 统计数据的差异(预计不会影响工作负载性能)是由于用于填充索引的算法不同。

15.6.2.4 InnoDB FULLTEXT索引

FULLTEXT 索引是在基于文本的列( CHAR VARCHAR TEXT 列) 上创建的 以帮助加快对这些列中包含的数据的查询和DML操作,省略任何定义为停用词的单词。

FULLTEXT 指数被定义为一个的一部分 CREATE TABLE 说明或使用添加到现有的表 ALTER TABLE CREATE INDEX

使用 MATCH() ... AGAINST 语法 执行全文搜索 有关使用信息,请参见 第12.9节“全文搜索功能”

InnoDB FULLTEXT 索引在本节的以下主题中描述:

InnoDB全文索引设计

InnoDB FULLTEXT 索引具有倒排索引设计。 反向索引存储单词列表,并为每个单词存储单词出现的文档列表。为了支持邻近搜索,还存储每个单词的位置信息,作为字节偏移量。

InnoDB全文索引表

创建 InnoDB FULLTEXT 索引时,会 创建 一组索引表,如以下示例所示:

MySQL的> CREATE TABLE opening_lines (
       id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
       opening_line TEXT(500),
       author VARCHAR(200),
       title VARCHAR(200),
       FULLTEXT idx (opening_line)
       ) ENGINE=InnoDB;

MySQL的> SELECT table_id, name, space from INFORMATION_SCHEMA.INNODB_TABLES
       WHERE name LIKE 'test/%';
+ ---------- + -------------------------------------- -------------- + ------- +
| table_id | 名字| 空间|
+ ---------- + -------------------------------------- -------------- + ------- +
| 333 | test / fts_0000000000000147_00000000000001c9_index_1 | 289 |
| 334 | test / fts_0000000000000147_00000000000001c9_index_2 | 290 |
| 335 | test / fts_0000000000000147_00000000000001c9_index_3 | 291 |
| 336 | test / fts_0000000000000147_00000000000001c9_index_4 | 292 |
| 337 | test / fts_0000000000000147_00000000000001c9_index_5 | 293 |
| 338 | test / fts_0000000000000147_00000000000001c9_index_6 | 294 |
| 330 | test / fts_0000000000000147_being_deleted | 286 |
| 331 | test / fts_0000000000000147_being_deleted_cache | 287 |
| 332 | test / fts_0000000000000147_config | 288 |
| 328 | test / fts_0000000000000147_deleted | 284 |
| 329 | test / fts_0000000000000147_deleted_cache | 285 |
| 327 | test / opening_lines | 283 |
+ ---------- + -------------------------------------- -------------- + ------- + 

前六个表表示反向索引,称为辅助索引表。 当传入文档被标记化时,单个词(也称为 标记 )与位置信息和关联的文档ID( DOC_ID 一起插入索引表中 根据单词第一个字符的字符集排序权重,对六个索引表中的单词进行完全排序和分区。

反向索引被划分为六个辅助索引表以支持并行索引创建。 默认情况下,两个线程对单词和关联数据进行标记,排序和插入索引表。 可以使用该 innodb_ft_sort_pll_degree 选项 配置线程数 FULLTEXT 在大型表上 创建 索引 时,请考虑增加线程数

辅助索引表名称带有前缀 fts_ 和后缀 index_* 每个索引表都通过索引表名称中与 table_id 索引表 匹配的十六进制值与索引表相关联 例如, table_id 所述的 test/opening_lines 表是 327 ,为此,十六进制值是0x147。 如前面的示例所示, 147 十六进制值出现在与表关联的索引表的名称中 test/opening_lines

表示的十六进制值 index_id 的的 FULLTEXT 索引也出现在辅助索引表名。 例如,在辅助表名称中 test/fts_0000000000000147_00000000000001c9_index_1 ,十六进制值 1c9 的十进制值为457. 可以通过查询 表中的值 来识别 opening_lines table( idx 上定义的索引 INFORMATION_SCHEMA.INNODB_INDEXES (457)。

MySQL的> SELECT index_id, name, table_id, space from INFORMATION_SCHEMA.INNODB_INDEXES
       WHERE index_id=457;
+ ---------- + ------ + ---------- + ------- +
| index_id | 名字| table_id | 空间|
+ ---------- + ------ + ---------- + ------- +
| 457 | idx | 327 | 283 |
+ ---------- + ------ + ---------- + ------- +

如果主表是在 每个表 文件表 空间中 创建的,则索引表存储在它们自己 的表 空间中。

前面示例中显示的其他索引表称为公共索引表,用于删除处理和存储 FULLTEXT 索引 的内部状态 与为每个全文索引创建的反向索引表不同,这组表对于在特定表上创建的所有全文索引是通用的。

即使删除了全文索引,也会保留公共辅助表。 删除全文索引时,将 FTS_DOC_ID 保留为索引创建的 FTS_DOC_ID ,因为删除 列将需要重建表。 管理 FTS_DOC_ID 色谱柱 需要常见的腋下表

  • fts_*_deleted fts_*_deleted_cache

    包含已删除但尚未从全文索引中删除其数据的文档的文档ID(DOC_ID)。 fts_*_deleted_cache fts_*_deleted 的内存版本

  • fts_*_being_deleted fts_*_being_deleted_cache

    包含已删除文档的文档ID(DOC_ID),其数据当前正在从全文索引中删除。 fts_*_being_deleted_cache 表是表的内存版本 fts_*_being_deleted

  • fts_*_config

    存储有关 FULLTEXT 索引 内部状态的信息 最重要的是,它存储了 FTS_SYNCED_DOC_ID 标识已解析并刷新到磁盘的文档。 在崩溃恢复的情况下, FTS_SYNCED_DOC_ID 值用于标识尚未刷新到磁盘的文档,以便可以重新解析文档并将其添加回 FULLTEXT 索引缓存。 要查看此表中的数据,请查询该 INFORMATION_SCHEMA.INNODB_FT_CONFIG 表。

InnoDB全文索引缓存

插入文档时,会对其进行标记化,并将单个单词和关联数据插入 FULLTEXT 索引中。 即使对于小型文档,此过程也可能导致在辅助索引表中进行大量小插入,从而使对这些表的并发访问成为争用的焦点。 要避免此问题,请 InnoDB 使用 FULLTEXT 索引缓存临时缓存最近插入的行的索引表插入。 此内存缓存结构保留插入,直到缓存已满,然后批量将它们刷新到磁盘(到辅助索引表)。 您可以查询该 INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE 表以查看最近插入的行的标记化数据。

缓存和批处理刷新行为避免了对辅助索引表的频繁更新,这可能导致繁忙的插入和更新时间期间的并发访问问题。 批处理技术还避免了对同一个单词的多次插入,并最大限度地减少了重复条目。 不是单独刷新每个单词,而是将同一个单词的插入合并并作为单个条目刷新到磁盘,从而提高插入效率,同时保持辅助索引表尽可能小。

innodb_ft_cache_size 变量用于配置全文索引缓存大小(基于每个表),这会影响全文索引缓存的刷新频率。 您还可以使用该 innodb_ft_total_cache_size 选项 为给定实例中的所有表定义全局全文索引缓存大小限制

全文索引缓存存储与辅助索引表相同的信息。 但是,全文索引缓存仅缓存最近插入的行的标记化数据。 已查询时,已刷新到磁盘(到全文辅助表)的数据不会返回到全文索引缓存中。 直接查询辅助索引表中的数据,并在返回之前将辅助索引表的结果与全文索引缓存的结果合并。

InnoDB全文索引文档ID和FTS_DOC_ID列

InnoDB 使用称为文档ID( DOC_ID 的唯一文档标识符将 全文索引中的单词映射到单词出现的文档记录。 映射需要 FTS_DOC_ID 索引表上的列。 如果 FTS_DOC_ID 未定义 列,则在创建全文索引时 InnoDB 自动添加隐藏 FTS_DOC_ID 列。 以下示例演示了此行为。

以下表定义不包括 FTS_DOC_ID 列:

MySQL的> CREATE TABLE opening_lines (
       id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
       opening_line TEXT(500),
       author VARCHAR(200),
       title VARCHAR(200)
       ) ENGINE=InnoDB;   

使用 CREATE FULLTEXT INDEX 语法 在表上创建全文索引时,将 返回一个警告,报告 InnoDB 正在重建表以添加 FTS_DOC_ID 列。

MySQL的> CREATE FULLTEXT INDEX idx ON opening_lines(opening_line);
查询正常,0行受影响,1警告(0.19秒)
记录:0重复:0警告:1

MySQL的> SHOW WARNINGS;
+ --------- + ------ + -------------------------------- ------------------ +
| 等级| 代码| 消息|
+ --------- + ------ + -------------------------------- ------------------ +
| 警告| 124 | InnoDB重建表添加列FTS_DOC_ID |
+ --------- + ------ + -------------------------------- ------------------ +

使用 ALTER TABLE 向没有 FTS_DOC_ID 的表添加全文索引 时,会返回相同的警告 如果您在 CREATE TABLE 时间 创建全文索引 并且未指定 FTS_DOC_ID 列,则 InnoDB 添加隐藏 FTS_DOC_ID 列,而不发出警告。

定时 FTS_DOC_ID 定义 CREATE TABLE 比在已加载数据的表上创建全文索引要便宜。 如果 FTS_DOC_ID 在加载数据之前在表上定义 列,则不必重建该表及其索引以添加新列。 如果您不关心 CREATE FULLTEXT INDEX 性能,请忽略该 FTS_DOC_ID 列以便 InnoDB 为您创建它。 InnoDB FTS_DOC_ID 列上 创建一个隐藏 列以及唯一索引( FTS_DOC_ID_INDEX FTS_DOC_ID 如果要创建自己的 FTS_DOC_ID 列,则必须将列定义为 BIGINT UNSIGNED NOT NULL 并命名 FTS_DOC_ID (全部大写),如下例所示:

注意

FTS_DOC_ID 列不需要定义为 AUTO_INCREMENT 列,但 AUTO_INCREMENT 可以使加载数据更容易。

MySQL的> CREATE TABLE opening_lines (
       FTS_DOC_ID BIGINT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
       opening_line TEXT(500),
       author VARCHAR(200),
       title VARCHAR(200)
       ) ENGINE=InnoDB;    

如果您选择自己定义 FTS_DOC_ID 列,则负责管理列以避免空值或重复值。 FTS_DOC_ID 值不能重用,这意味着 FTS_DOC_ID 值必须不断增加。

(可选)您可以 FTS_DOC_ID_INDEX FTS_DOC_ID 创建所需的唯一 (全部大写)

MySQL的> CREATE UNIQUE INDEX FTS_DOC_ID_INDEX on opening_lines(FTS_DOC_ID);

如果您不创建 FTS_DOC_ID_INDEX InnoDB 则自动创建。

注意

FTS_DOC_ID_INDEX 不能定义为降序索引,因为 InnoDB SQL解析器不使用降序索引。

最大使用 FTS_DOC_ID 值与新 FTS_DOC_ID 之间的允许间隔 为65535。

为避免重建表, FTS_DOC_ID 删除全文索引时将保留 列。

InnoDB全文索引删除处理

删除具有全文索引列的记录可能会导致辅助索引表中出现大量小删除,从而使这些表的并发访问成为争用的焦点。 为避免此问题, 每当从索引表中删除 DOC_ID 记录时,已删除文档 的文档ID( )都会记录在特殊 FTS_*_DELETED 表中,并且索引记录将保留在全文索引中。 在返回查询结果之前,信息在 FTS_*_DELETED table用于过滤掉已删除的文档ID。 这种设计的好处是删除快速且廉价。 缺点是删除记录后索引的大小不会立即减少。 要删除已删除记录的全文索引条目,请 OPTIMIZE TABLE 在索引表上 运行 innodb_optimize_fulltext_only=ON 以重建全文索引。 有关更多信息,请参阅 优化InnoDB全文索引

InnoDB全文索引事务处理

InnoDB FULLTEXT 由于其缓存和批处理行为,索引具有特殊的事务处理特性。 具体而言, FULLTEXT 在事务提交时处理索引 上的更新和插入 ,这意味着 FULLTEXT 搜索只能看到已提交的数据。 以下示例演示了此行为。 FULLTEXT 搜索只返回插入的行被提交之后的结果。

MySQL的> CREATE TABLE opening_lines (
       id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
       opening_line TEXT(500),
       author VARCHAR(200),
       title VARCHAR(200),
       FULLTEXT idx (opening_line)
       ) ENGINE=InnoDB;

MySQL的> BEGIN;

MySQL的> INSERT INTO opening_lines(opening_line,author,title) VALUES
       ('Call me Ishmael.','Herman Melville','Moby-Dick'),
       ('A screaming comes across the sky.','Thomas Pynchon','Gravity\'s Rainbow'),
       ('I am an invisible man.','Ralph Ellison','Invisible Man'),
       ('Where now? Who now? When now?','Samuel Beckett','The Unnamable'),
       ('It was love at first sight.','Joseph Heller','Catch-22'),
       ('All this happened, more or less.','Kurt Vonnegut','Slaughterhouse-Five'),
       ('Mrs. Dalloway said she would buy the flowers herself.','Virginia Woolf','Mrs. Dalloway'),
       ('It was a pleasure to burn.','Ray Bradbury','Fahrenheit 451');

MySQL的> SELECT COUNT(*) FROM opening_lines WHERE MATCH(opening_line) AGAINST('Ishmael');
+ ---------- +
| COUNT(*)|
+ ---------- +
| 0 |
+ ---------- +

MySQL的> COMMIT;

MySQL的> SELECT COUNT(*) FROM opening_lines WHERE MATCH(opening_line) AGAINST('Ishmael');
+ ---------- +
| COUNT(*)|
+ ---------- +
| 1 |
+ ---------- +
监控InnoDB全文索引

您可以 InnoDB FULLTEXT 通过查询以下 INFORMATION_SCHEMA 来监视和检查 索引 的特殊文本处理方面

您还可以 FULLTEXT 通过查询 INNODB_INDEXES 查看 索引和表的 基本信息 INNODB_TABLES

有关更多信息,请参见 第15.14.4节“InnoDB INFORMATION_SCHEMA FULLTEXT索引表”

15.6.3表空间

本节介绍与 InnoDB 表空间 相关的主题

15.6.3.1系统表空间

InnoDB 系统表空间的双写缓冲区和改变缓冲存储区。 系统表空间还包含在系统表空间中创建的用户创建表的表和索引数据。 在以前的版本中,系统表空间包含 InnoDB 数据字典。 在MySQL 8.0中, InnoDB 将元数据存储在MySQL数据字典中。 请参见 第14章, MySQL数据字典

系统表空间可以包含一个或多个数据文件。 默认情况下, ibdata1 在数据目录中创建 一个名为的系统表空间数据文件 系统表空间数据文件的大小和数量由 innodb_data_file_path 启动选项 控制 有关相关信息,请参阅 系统表空间数据文件配置

调整系统表空间的大小

本节介绍如何增大或减小 InnoDB 系统表空间 的大小

增加InnoDB系统表空间的大小

增加 InnoDB 系统表空间 大小的最简单方法 是从头开始配置它以自动扩展。 autoextend 在表空间定义中 指定 最后一个数据文件 属性。 然后 InnoDB 在空间不足时以64MB为增量自动增加该文件的大小。 可以通过设置 innodb_autoextend_increment 系统变量 的值来更改增量大小,该值 以兆字节为单位。

您可以通过添加另一个数据文件将系统表空间扩展一个定义的数量:

  1. 关闭MySQL服务器。

  2. 如果使用关键字定义了上一个最后一个数据文件 autoextend ,请根据实际增长的大小将其定义更改为使用固定大小。 检查数据文件的大小,将其向下舍入到1024×1024字节(= 1MB)的最接近倍数,并明确指定此舍入大小 innodb_data_file_path

  3. 添加新数据文件到末尾 innodb_data_file_path ,可选择使该文件自动扩展。 只能将最后一个数据文件 innodb_data_file_path 指定为自动扩展。

  4. 再次启动MySQL服务器。

例如,此表空间只有一个自动扩展数据文件 ibdata1

innodb_data_home_dir =
innodb_data_file_path = / ibdata / ibdata1:10M:autoextend

假设这个数据文件随着时间的推移已增长到988MB。 以下是修改原始数据文件以使用固定大小并添加新的自动扩展数据文件后的配置行:

innodb_data_home_dir =
innodb_data_file_path = / ibdata / ibdata1:988M; / disk2 / ibdata2:50M:autoextend

将新数据文件添加到系统表空间配置时,请确保文件名不引用现有文件。 InnoDB 重新启动服务器时创建并初始化文件。

减小InnoDB系统表空间的大小

您无法从系统表空间中删除数据文件。 要减小系统表空间大小,请使用以下过程:

  1. 使用 mysqldump 转储所有 InnoDB 表,包括 InnoDB 位于MySQL数据库中的表。

    MySQL的> SELECT TABLE_NAME from INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='mysql' and ENGINE='InnoDB';
    + --------------------------- +
    | TABLE_NAME |
    + --------------------------- +
    | columns_priv |
    | 组件|
    | db |
    | default_roles |
    | engine_cost |
    | func |
    | global_grants |
    | gtid_executed |
    | help_category |
    | help_keyword |
    | help_relation |
    | help_topic |
    | innodb_dynamic_metadata |
    | innodb_index_stats |
    | innodb_table_stats |
    | 插件|
    | procs_priv |
    | proxies_priv |
    | role_edges |
    | server_cost |
    | 服务器|
    | slave_master_info |
    | slave_relay_log_info |
    | slave_worker_info |
    | tables_priv |
    | time_zone |
    | time_zone_leap_second |
    | time_zone_name |
    | time_zone_transition |
    | time_zone_transition_type |
    | 用户|
    + --------------------------- +
    
  2. 停止服务器。

  3. 删除所有现有的表空间文件( *.ibd ),包括 ibdata ib_log 文件。 不要忘记删除 *.ibd 位于MySQL数据库中的表的文件。

  4. 配置新的表空间。

  5. 重启服务器。

  6. 导入转储文件。

注意

如果您的数据库仅使用 InnoDB 引擎,则转储 所有 数据库,停止服务器,删除所有数据库和 InnoDB 日志文件,重新启动服务器以及导入转储文件 可能更简单

为系统表空间使用原始磁盘分区

您可以将原始磁盘分区用作 InnoDB 系统表空间 中的数据文件 此技术可在Windows和某些Linux和Unix系统上启用非缓冲I / O,而无需文件系统开销。 使用和不使用原始分区执行测试以验证此更改是否实际上提高了系统性能。

使用原始磁盘分区时,请确保运行MySQL服务器的用户标识具有该分区的读写权限。 例如,如果以 mysql 用户 身份运行服务器 ,则该分区必须是可读写的 mysql 如果使用该 --memlock 选项 运行服务器 ,则必须运行服务器 root ,因此该分区必须是可读写的 root

下面描述的过程涉及选项文件修改。 有关其他信息,请参见 第4.2.2.2节“使用选项文件”

在Linux和Unix系统上分配原始磁盘分区
  1. 创建新数据文件时,请在 newraw innodb_data_file_path 选项 的数据文件大小之后立即 指定关键字 分区必须至少与指定的大小一样大。 请注意,1MB in InnoDB 是1024×1024字节,而磁盘规格中的1MB通常意味着1,000,000字节。

    的[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系统的相同步骤和附带指南适用,但 innodb_data_file_path Windows上 设置稍有不同。

  1. 创建新数据文件时,请在 newraw innodb_data_file_path 选项 的数据文件大小之后立即 指定关键字

    的[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 现在允许进行更改。

15.6.3.2每表文件表空间

从历史上看, InnoDB 表存储在 系统表空间中 这种单片方法针对专用于数据库处理的机器,精心规划数据增长,其中任何分配给MySQL的磁盘存储都不会用于其他目的。 每个表 文件表空间 功能提供了更灵活的替代方案,其中每个 InnoDB 表都存储在自己的表空间数据文件( .ibd 文件)中。 此功能由 innodb_file_per_table 配置选项 控制 ,默认情况下启用 选项。

好处
  • 截断或删除存储在每个表文件表空间中的表时,可以回收磁盘空间。 截断或删除存储在共享 系统表空间中的表 会在系统表空间数据文件( ibdata文件 内部创建可用空间,该数据文件 只能用于新 InnoDB 数据。

    类似地, ALTER TABLE 驻留在共享表空间中的表上的表 复制 操作可以增加表空间使用的空间量。 此类操作可能需要与表中的数据和索引一样多的额外空间。 表复制 ALTER TABLE 操作 所需的额外空间 不会像文件每表表空间一样释放回操作系统。

  • TRUNCATE TABLE 在存储在每个表文件表空间中的表上运行时 操作更快。

  • 您可以通过使用语法指定每个表的位置,将特定表存储在单独的存储设备上,进行I / O优化,空间管理或备份 ,如 第15.6.3.6节“在数据目录外创建表空间”中所述“ CREATE TABLE ... DATA DIRECTORY = absolute_path_to_directory

  • 您可以运行 OPTIMIZE TABLE 以压缩或重新创建每个表的文件表空间。 当您运行 OPTIMIZE TABLE InnoDB 创建一个新的 .ibd 具有临时名称的文件,只使用存储的实际数据所需的空间。 优化完成后, InnoDB 删除旧 .ibd 文件并将其替换为新文件。 如果前一个 .ibd 文件显着增长但实际数据仅占其大小的一部分,则运行 OPTIMIZE TABLE 可以回收未使用的空间。

  • 您可以移动单个 InnoDB 表而不是整个数据库。

  • 您可以将单个 InnoDB 表从一个MySQL实例 复制 到另一个MySQL实例(称为可 传输表空间 功能)。

  • 以每表文件表空间创建的表支持与 压缩 动态 行格式 相关的功能

  • 您可以 使用 动态行格式 为具有大型 BLOB TEXT 列的 表启用更高效的存储

  • 每个表的文件表空间可以提高成功恢复的机会,并在发生损坏,无法重新启动服务器或备份和二进制日志不可用时节省时间。

  • 您可以使用MySQL Enterprise Backup产品快速备份或还原单个表,而不会中断其他 InnoDB 的使用 如果您的表需要较少的备份或不同的备份计划,这将非常有用。 有关 详细信息, 请参阅 进行部分备份

  • 在复制或备份表时,每表文件表空间便于每表状态报告。

  • 您可以在不访问MySQL的情况下监视文件系统级别的表大小。

  • innodb_flush_method 设置为 常用Linux文件系统时,不允许对单个文件进行并发写入 O_DIRECT 因此,在结合使用每表文件表空间时,可能会有性能提升 innodb_flush_method

  • 系统表空间存储数据字典和撤消日志,并且受 InnoDB 表空间大小限制的限制。 请参见 第15.6.1.6节“InnoDB表的限制” 使用每表文件表空间,每个表都有自己的表空间,这为增长提供了空间。

潜在的缺点
  • 对于每个表的文件表空间,每个表可能有未使用的空间,只能由同一个表的行使用。 如果管理不当,这可能会导致空间浪费。

  • fsync 操作必须在每个打开的表上运行,而不是在单个文件上运行。 由于 fsync 每个文件 都有单独的 操作,因此不能将多个表上的写操作组合到单个I / O操作中。 这可能需要 InnoDB 执行更高的 fsync 操作 总数

  • mysqld 必须为每个表保留一个打开的文件句柄,如果在每个表的文件表空间中有许多表,这可能会影响性能。

  • 使用更多文件描述符。

  • innodb_file_per_table 在MySQL 5.6及更高版本中默认启用。 如果与早期版本的MySQL向后兼容是一个问题,您可以考虑禁用它。

  • 如果许多表正在增长,则可能存在更多碎片,这可能会妨碍 DROP TABLE 表扫描性能。 但是,在管理碎片时,在自己的表空间中放置文件可以提高性能。

  • 删除每个表的文件表空间时会扫描缓冲池,对于数十GB的缓冲池,这可能需要几秒钟。 使用广泛的内部锁执行扫描,这可能会延迟其他操作。 系统表空间中的表不受影响。

  • innodb_autoextend_increment 变量定义了增量大小(以MB为单位),用于在自动扩展的共享表空间文件变满时扩展其大小,不适用于每个表文件的表空间文件,无论 innodb_autoextend_increment 设置 如何,这些文件都是自动扩展的 初始扩展是少量的,之后扩展以4MB的增量发生。

启用每个表的文件表空间

innodb_file_per_table 默认情况下启用 选项。

innodb_file_per_table 在启动时 设置 选项,请使用 --innodb_file_per_table 命令行选项 启动服务器 ,或将此行添加到以下 [mysqld] 部分 my.cnf

的[mysqld]
innodb_file_per_table = 1

您还可以 innodb_file_per_table 在服务器运行时动态 设置

MySQL的> SET GLOBAL innodb_file_per_table=1;

innodb_file_per_table 启用,可以存储 InnoDB 在一个表 tbl_name.ibd 文件。 不同于 MyISAM 存储引擎,与它的独立 tbl_name.MYD tbl_name.MYI 文件进行索引和数据, InnoDB 在一个单一的数据和索引存储在一起 .ibd 的文件。

如果 innodb_file_per_table 在启动选项中 禁用 并重新启动服务器,或使用该 SET GLOBAL 命令 禁用它,则 InnoDB 在系统表空间内创建新表,除非您已使用该 CREATE TABLE ... TABLESPACE 选项 将表显式放置在每表文件表空间或通用表空间中

InnoDB 无论每个表的文件设置如何, 您始终可以读写任何 表。

要将表从系统表空间移动到其自己的表空间,请更改 innodb_file_per_table 设置并重建表:

mysql> SET GLOBAL innodb_file_per_table=1;
mysql>ALTER TABLE table_name ENGINE=InnoDB;

使用 CREATE TABLE ... TABLESPACE ALTER TABLE ... TABLESPACE 语法 添加到系统表空间的表 不受 innodb_file_per_table 设置的 影响 要将这些表从系统表空间移动到每个表的文件表空间,必须使用 ALTER TABLE ... TABLESPACE 语法 显式移动它们

注意

InnoDB 总是需要系统表空间,因为它将内部 数据字典 撤消日志 放在 那里。 这些 .ibd 文件不足以 InnoDB 运行。

将表从系统表空间移出到其自己的 .ibd 文件中时,组成系统表空间的数据文件大小保持不变。 以前由表占用的空间可以重新用于新 InnoDB 数据,但不会被回收以供操作系统使用。 将大 InnoDB 表移出磁盘空间有限的系统表空间时,您可能更喜欢 innodb_file_per_table 使用 mysqldump 命令 启用 并重新创建整个实例 如上所述,使用 CREATE TABLE ... TABLESPACE ALTER TABLE ... TABLESPACE 语法 添加到系统表空间的表 不受 innodb_file_per_table 设置。 必须单独移动这些表。

15.6.3.3一般表空间

通用表空间是 InnoDB 使用 CREATE TABLESPACE 语法 创建 的共享 表空间 本节中的以下主题描述了常规表空间功能和功能:

一般表空间功能

通用表空间功能提供以下功能:

  • 与系统表空间类似,通用表空间是可以存储多个表的数据的共享表空间。

  • 与基于 文件的表空间 相比,常规表空间具有潜在的内存优势 服务器在表空间的生命周期内将表空间元数据保存在内存中。 较少的通用表空间中的多个表对表空间元数据的内存消耗比单独的每个表文件表空间中的相同数量的表少。

  • 通用表空间数据文件可以放在相对于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
    [添加数据文件' file_name']
    [FILE_BLOCK_SIZE = value]
        [ENGINE [=] engine_name]

可以在数据目录中或在其外部创建常规表空间。 为避免与隐式创建的每表文件表空间冲突,不支持在数据目录下的子目录中创建常规表空间。 在数据目录之外创建通用表空间时,该目录必须存在,并且必须 InnoDB 在创建表空间之前 知道 要创建已知的未知目录 InnoDB ,请将该目录添加到 innodb_directories 参数值。 innodb_directories 是一个只读启动选项。 配置它需要重新启动服务器。

例子:

在数据目录中创建常规表空间:

MySQL的> CREATE TABLESPACE `ts1` ADD DATAFILE 'ts1.ibd' Engine=InnoDB;

要么

MySQL的> CREATE TABLESPACE `ts1` Engine=InnoDB;

ADD DATAFILE 子句在MySQL 8.0.14中是可选的,在此之前是必需的。 如果 ADD DATAFILE 在创建表空间时未指定子句,则会隐式创建具有唯一文件名的表空间数据文件。 唯一文件名是128位UUID,格式化为由破折号( aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee 分隔的五组十六进制数字 常规表空间数据文件包括 .ibd 文件扩展名。 在复制环境中,在主服务器上创建的数据文件名与在从服务器上创建的数据文件名不同。

在数据目录之外的目录中创建常规表空间:

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 8.0.13中删除了。 共享表空间包括 InnoDB 系统表空间和通用表空间。

有关详细语法信息,请参阅 CREATE TABLE ALTER TABLE

常规表空间行格式支持

一般的表空间支持所有表行格式( REDUNDANT COMPACT DYNAMIC COMPRESSED )与压缩和非压缩表不能在同一个表空间一般共存的警告,由于不同的物理页面大小。

对于包含压缩表( ROW_FORMAT=COMPRESSED 的常规表空间 FILE_BLOCK_SIZE 必须指定,并且该 FILE_BLOCK_SIZE 值必须是 与该 值相关的有效压缩页大小 innodb_page_size 此外,压缩表( KEY_BLOCK_SIZE 的物理页面大小 必须等于 FILE_BLOCK_SIZE/1024 例如,如果 innodb_page_size=16KB FILE_BLOCK_SIZE=8K KEY_BLOCK_SIZE 表的必须为8。

下表显示了允许的 innodb_page_size FILE_BLOCK_SIZE KEY_BLOCK_SIZE 组合。 FILE_BLOCK_SIZE 值也可以以字节为单位指定。 要确定 KEY_BLOCK_SIZE 给定 的有效值 FILE_BLOCK_SIZE ,请将 FILE_BLOCK_SIZE 值除以1024.表压缩不支持32K和64K InnoDB 页面大小。 有关的更多信息 KEY_BLOCK_SIZE ,请参见 CREATE TABLE 第15.9.1.2节“创建压缩表”

表15.4压缩表的允许页大小,FILE_BLOCK_SIZE和KEY_BLOCK_SIZE组合

InnoDB页面大小(innodb_page_size) 允许的FILE_BLOCK_SIZE值 允许的KEY_BLOCK_SIZE值
64KB 64K(65536) 不支持压缩
32KB 32K(32768) 不支持压缩
16KB 16K(16384) N / A:如果 innodb_page_size 等于 FILE_BLOCK_SIZE ,则表空间不能包含压缩表。
16KB 8K(8192) 8
16KB 4K(4096) 4
16KB 2K(2048) 2
16KB 1K(1024) 1
8KB 8K(8192) N / A:如果 innodb_page_size 等于 FILE_BLOCK_SIZE ,则表空间不能包含压缩表。
8KB 4K(4096) 4
8KB 2K(2048) 2
8KB 1K(1024) 1
4KB 4K(4096) N / A:如果 innodb_page_size 等于 FILE_BLOCK_SIZE ,则表空间不能包含压缩表。
4KB 2K(2048) 2
4KB 1K(1024) 1

此示例演示如何创建常规表空间并添加压缩表。 该示例假定默认 innodb_page_size 值为16KB。 FILE_BLOCK_SIZE 8192要求压缩表有 KEY_BLOCK_SIZE 8个。

MySQL的> CREATE TABLESPACE `ts2` ADD DATAFILE 'ts2.ibd' FILE_BLOCK_SIZE = 8192 Engine=InnoDB;

MySQL的> CREATE TABLE t4 (c1 INT PRIMARY KEY) TABLESPACE ts2 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;

如果未指定 FILE_BLOCK_SIZE 何时创建常规表空间,则 FILE_BLOCK_SIZE 默认为 innodb_page_size FILE_BLOCK_SIZE 等于 innodb_page_size ,表空间可能只包含与未压缩的行格式(表 COMPACT REDUNDANT DYNAMIC 行格式)。

使用ALTER TABLE在表空间之间移动表

您可以使用 ALTER TABLE TABLESPACE 选项将表移动到现有的通用表空间,新的每个表文件表空间或系统表空间。

注意

在MySQL 5.7.24中不支持在共享表空间中放置表分区,并删除了MySQL 8.0.13。 共享表空间包括 InnoDB 系统表空间和通用表空间。

要将表从每个表的文件表空间或从系统表空间移动到常规表空间,请指定常规表空间的名称。 通用表空间必须存在。 有关 CREATE 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;

ALTER TABLE ... TABLESPACE 即使 TABLESPACE 属性未从其先前值更改, 操作也始终会导致完整表重建

ALTER TABLE ... TABLESPACE 语法不支持将表从临时表空间移动到持久表空间。

DATA DIRECTORY 条款是允许的, CREATE TABLE ... TABLESPACE=innodb_file_per_table 但不支持与该 TABLESPACE 选项一起使用。

从加密表空间移动表时适用限制。 请参阅 加密限制

重命名常规表空间

使用 ALTER TABLESPACE ... RENAME TO 语法 支持重命名通用表空间

ALTER TABLESPACE s1重命名为s2;

CREATE TABLESPACE 重命名常规表空间需要 权限。

RENAME TO autocommit 无论 autocommit 设置 如何, 都以 模式 隐式执行操作

RENAME TO 操作不能同时被执行 LOCK TABLES 或者 FLUSH TABLES WITH READ LOCK 是在驻留在表空间的表的效果。

在重命名表空间时,会对通用表空间中的表执行 独占 元数据锁定 ,从而防止并发DDL。 支持并发DML。

删除常规表空间

DROP TABLESPACE 语句用于删除 InnoDB 常规表空间。

必须在 DROP TABLESPACE 操作 之前从表空间中删除所有表 如果表空间不为空,则 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 |
+ ------------ + ------------ +

InnoDB 删除表空间中的最后一个表时,不会自动删除 常规 表空间。 必须使用显式删除表空间 DROP TABLESPACE tablespace_name

通用表空间不属于任何特定数据库。 一个 DROP DATABASE 操作可以丢弃属于一般的表空间的表,但它不能删除表空间,即使 DROP DATABASE 操作下降属于该表空间中的所有表。 必须使用显式删除常规表空间 DROP TABLESPACE tablespace_name

与系统表空间类似,截断或删除存储在通用表空间中的表会在通用表空间 .ibd数据文件 内部创建可用空间,该 文件 只能用于新 InnoDB 数据。 空间不会释放回操作系统,因为在 DROP TABLE 操作 期间删除了每表文件表空间

此示例演示如何删除 InnoDB 常规表空间。 ts1 使用单个表创建 常规表空间 在删除表空间之前必须删除该表。

MySQL的> CREATE TABLESPACE `ts1` ADD DATAFILE 'ts1.ibd' Engine=InnoDB;

MySQL的> CREATE TABLE t1 (c1 INT PRIMARY KEY) TABLESPACE ts10 Engine=InnoDB;

MySQL的> DROP TABLE t1;

MySQL的> DROP TABLESPACE ts1;
注意

tablespace_name 是MySQL中区分大小写的标识符。

一般表空间限制
  • 生成的或现有的表空间不能更改为常规表空间。

  • 不支持创建临时通用表空间。

  • 常规表空间不支持临时表。

  • 与系统表空间类似,截断或删除存储在通用表空间中的表会在通用表空间 .ibd数据文件 内部创建可用空间,该 文件 只能用于新 InnoDB 数据。 空间不会像 文件每表表 空间 一样释放回操作系统

    此外, ALTER TABLE 驻留在共享表空间(通用表空间或系统表空间)中的表上的表 复制 操作可以增加表空间使用的空间量。 此类操作需要与表中的数据和索引一样多的额外空间。 表复制 ALTER TABLE 操作 所需的额外空间 不会像文件每表表空间一样释放回操作系统。

  • ALTER TABLE ... DISCARD TABLESPACE 并且 ALTER TABLE ...IMPORT TABLESPACE 不支持属于常规表空间的表。

  • 支持在一般表空间中放置表分区在MySQL 5.7.24中已弃用,在MySQL 8.0.13中已删除。

15.6.3.4撤消表空间

撤消表空间包含撤消日志,撤消日志是撤消日志记录的集合,其中包含有关如何撤消事务到聚簇索引记录的最新更改的信息。 撤消日志存在于撤消日志段中,这些日志段包含在回滚段中。 innodb_rollback_segments 变量定义分配给每个撤消表空间的回滚段数。

初始化MySQL实例时会创建两个默认的撤消表空间。 在初始化时创建默认的撤消表空间,以便为可以接受SQL语句之前必须存在的回滚段提供位置。 至少需要两个撤消表空间才能支持自动截断撤消表空间。 请参阅 截断撤消表空间

innodb_undo_directory 变量 定义的位置创建默认的撤消表空间 如果 innodb_undo_directory 变量未定义,则在数据目录中创建默认的撤消表空间。 默认的undo表空间数据文件名为 undo_001 and undo_002 数据字典中定义的相应撤消表空间名称是 innodb_undo_001 innodb_undo_002

从MySQL 8.0.14开始,可以使用SQL在运行时创建其他撤消表空间。 请参阅 添加撤消表空间

undo表空间数据文件的初始大小取决于 innodb_page_size 值。 对于默认的16KB页面大小,初始撤消表空间文件大小为10MiB。 对于4KB,8KB,32KB和64KB页面大小,初始撤消表空间文件大小分别为7MiB,8MiB,20MiB和40MiB。

添加撤消表空间

由于在长时间运行的事务期间撤消日志可能会变大,因此创建其他撤消表空间可以帮助防止单个撤消表空间变得过大。 从MySQL 8.0.14开始,可以使用 CREATE UNDO TABLESPACE 语法 在运行时创建其他撤消表空间

创建UNDO TABLESPACE tablespace_name添加数据文件' file_name.ibu'     

撤消表空间文件名必须具有 .ibu 扩展名。 在定义撤消表空间文件名时,不允许指定相对路径。 允许使用完全限定的路径,但必须知道路径 InnoDB 已知路径是由 innodb_directories 变量 定义的路径

在启动时, innodb_directories 将扫描变量 定义的目录以 获取撤消表空间文件。 (扫描也横穿子目录。)由定义的目录 innodb_data_home_dir innodb_undo_directory datadir 变量被自动添加到 innodb_directories 值,而不管是否 innodb_directories 变量被明确定义。 因此,撤消表空间可以驻留在由任何这些变量定义的路径中。

如果undo表空间文件名不包含路径,则会在 innodb_undo_directory 变量 定义的目录中创建undo表空间 如果未定义该变量,则会在数据目录中创建撤消表空间。

注意

InnoDB 恢复过程要求撤销表空间文件驻留在已知的目录。 必须在重做恢复之前和打开其他数据文件之前发现并打开撤消表空间文件,以允许回滚未提交的事务和数据字典更改。 无法使用恢复前未找到的撤消表空间,这可能导致数据库不一致。 如果未找到数据字典已知的撤消表空间,则在启动时会报告错误消息。 已知的目录要求还支持撤消表空间可移植性。 请参阅 移动撤消表空间

要在相对于数据目录的路径中创建撤消表空间,请将 innodb_undo_directory 变量设置为相对路径,并仅在创建撤消表空间时指定文件名。

要查看撤消表空间名称和路径,请查询 INFORMATION_SCHEMA.FILES

来自INFORMATION_SCHEMA.FILES的SELECT TABLESPACE_NAME,FILE_NAME 
  FILE_TYPE喜欢'UNDO LOG';

MySQL实例最多支持127个undo表空间,包括MySQL实例初始化时创建的两个默认undo表空间。

注意

在MySQL 8.0.14之前,通过配置 innodb_undo_tablespaces 启动变量 来创建其他撤消表空间 不推荐使用此变量,不再可以从MySQL 8.0.14开始配置。

在MySQL 8.0.14之前,增加 innodb_undo_tablespaces 设置会创建指定数量的撤消表空间,并将它们添加到活动撤消表空间列表中。 减小 innodb_undo_tablespaces 设置会从活动的撤消表空间列表中删除撤消表空间。 从活动列表中删除的撤消表空间保持活动状态,直到现有事务不再使用它们。 所述 innodb_undo_tablespaces 变量可以在运行时使用一被配置 SET 陈述或在配置文件中定义。

在MySQL 8.0.14之前,无法删除已停用的撤消表空间。 在缓慢关闭后可以手动删除撤消表空间文件但不建议这样做,因为如果在关闭服务器时存在打开的事务,则在重新启动服务器后的一段时间内,停用的撤消表空间可能包含活动的撤消日志。 从MySQL 8.0.14开始,可以使用 DROP UNDO TABALESPACE 语法 删除撤消表空间 请参阅 删除撤消表空间

删除撤消表空间

从MySQL 8.0.14开始, CREATE UNDO TABLESPACE 可以 使用 语法在运行时删除 使用 语法 创建的撤消表空间 DROP UNDO TABALESPACE

撤消表空间在删除之前必须为空。 要清空撤消表空间,必须首先使用 ALTER UNDO TABLESPACE 语法 将撤消表空间标记为非活动, 以便不再使用表空间将回滚段分配给新事务。

ALTER UNDO TABLESPACE tablespace_nameSET INACTIVE;       

将撤消表空间标记为非活动后,允许完成当前在撤消表空间中使用回滚段的事务,以及在这些事务完成之前启动的任何事务。 事务完成后,清除系统将释放撤消表空间中的回滚段,并将撤消表空间截断为其初始大小。 (截断撤消表空间时使用相同的过程。请参阅 截断撤消表空间 。)当撤消表空间为空时,可以删除它。

DROP UNDO TABLESPACE tablespace_name;
注意

或者,撤消表空间可以保留为空状态,并在需要时通过发出 语句 稍后重新激活 ALTER UNDO TABLESPACE tablespace_name SET ACTIVE

可以通过查询 INFORMATION_SCHEMA.INNODB_TABLESPACES 来监视撤消表空间的状态

SELECT NAME,STATE FROM INFORMATION_SCHEMA.INNODB_TABLESPACES 
  名称在哪里tablespace_name;

inactive 状态表示在撤销表空间回滚段不再使用新的交易。 一个 empty 状态指示UNDO表空间是空的,并准备好被丢弃或再使用作出了积极 发言。 尝试删除非空的撤消表空间会返回错误。 ALTER UNDO TABLESPACE tablespace_name SET ACTIVE

无法删除MySQL实例初始化时创建 的默认撤消表空间( innodb_undo_001 innodb_undo_002 )。 但是,可以使用 声明 使它们处于非活动状态 在默认撤消表空间可以处于非活动状态之前,必须有一个撤消表空间来取代它。 始终至少需要两个活动的撤消表空间,以支持自动截断撤消表空间。 ALTER UNDO TABLESPACE tablespace_name SET INACTIVE

移动撤消表空间

使用 CREATE UNDO TABLESPACE 语法 创建的撤消表空间 可以在服务器脱机时移动到任何已知目录。 已知目录是由 innodb_directories 变量 定义的目录 无论是否 明确定义变量 innodb_data_home_dir 定义的目录 innodb_undo_directory ,以及 datadir 自动附加到 innodb_directories 值的目录 innodb_directories 在启动时扫描这些目录及其子目录以获取撤消表空间文件。 在启动时发现移动到任何这些目录的撤消表空间文件,并假定它是已移动的撤消表空间。

初始化MySQL实例时创建 的默认撤消表空间( innodb_undo_001 innodb_undo_002 )必须始终位于 innodb_undo_directory 变量 定义的目录中 如果 innodb_undo_directory 变量未定义,则默认的undo表空间将驻留在数据目录中。 如果在服务器脱机时移动了默认的撤消表空间,则必须使用 innodb_undo_directory 配置到新目录 变量 启动服务器

撤消日志的I / O模式使撤消表空间成为 SSD 存储的 良好候选者

配置回滚段数

innodb_rollback_segments 变量定义 分配给每个撤消表空间和全局临时表空间 回滚段 innodb_rollback_segments 变量可以在启动时被配置为或在服务器正在运行。

默认设置为 innodb_rollback_segments 128,也是最大值。 有关回滚段支持的事务数的信息,请参见 第15.6.6节“撤消日志”

截断撤消表空间

有两种截断撤消表空间的方法,可以单独使用或组合使用来管理撤消表空间大小。 一种方法是自动化的,使用配置变量启用。 另一种方法是手动,使用SQL语句执行。

自动方法不需要监视撤消表空间大小,并且一旦启用,它就会执行撤消,截断和重新激活撤消表空间,而无需手动干预。 如果要控制撤消表空间何时脱机以进行截断,则手动截断方法可能更为可取。 例如,您可能希望避免在高峰工作负载时间截断撤消表空间。

自动截断

undo表空间的自动截断至少需要两个活动的undo表空间,这样可以确保一个undo表空间保持活动状态,而另一个表空间处于脱机状态以进行截断。 缺省情况下,MySQL实例初始化时会创建两个undo表空间。

要自动截断撤消表空间,请启用该 innodb_undo_log_truncate 变量。 例如:

MySQL的> SET GLOBAL innodb_undo_log_truncate=ON;

innodb_undo_log_truncate 被使能可变的,撤消超过由所定义的大小限制表空间 innodb_max_undo_log_size 变量受到截断。 innodb_max_undo_log_size 变量是动态的,默认值为1073741824字节(1024 MiB)。

MySQL的> SELECT @@innodb_max_undo_log_size;
+ ---------------------------- +
| @@ innodb_max_undo_log_size |
+ ---------------------------- +
| 1073741824 |
+ ---------------------------- +

innodb_undo_log_truncate 启用变量:

  1. 超出 innodb_max_undo_log_size 设置的 默认和用户定义的撤消表空间 标记为截断。 选择用于截断的撤消表空间以循环方式执行,以避免每次都截断相同的撤消表空间。

  2. 驻留在所选撤消表空间中的回滚段将变为非活动状态,以便不将它们分配给新事务。 允许当前使用回滚段的现有事务完成。

  3. 净化 系统释放回滚段不再使用。

  4. 释放撤消表空间中的所有回滚段后,将运行truncate操作并将undo表空间截断为其初始大小。 undo表空间的初始大小取决于 innodb_page_size 值。 对于默认的16KB页面大小,初始撤消表空间文件大小为10MiB。 对于4KB,8KB,32KB和64KB页面大小,初始撤消表空间文件大小分别为7MiB,8MiB,20MiB和40MiB。

    由于在操作完成后立即使用,截断操作之后的撤消表空间的大小可能大于初始大小。

    innodb_undo_directory 变量定义了默认undo表空间文件的位置。 如果 innodb_undo_directory 变量未定义,则默认的undo表空间将驻留在数据目录中。 CREATE UNDO TABLESPACE 可以通过查询 INFORMATION_SCHEMA.FILES 来确定 所有撤消表空间文件的位置,包括使用 语法 创建的用户定义的撤消表空间

    SELECT TABLESPACE_NAME,FILE_NAME来自INFORMATION_SCHEMA.FILES,其中FILE_TYPE喜欢'UNDO LOG';
  5. 重新激活回滚段,以便将它们分配给新事务。

手动截断

手动截断撤消表空间至少需要三个活动的撤消表空间。 始终需要两个活动的撤消表空间,以支持启用自动截断的可能性。 至少有三个撤消表空间满足此要求,同时允许撤消表空间手动脱机。

要手动启动撤消表空间的截断,请通过发出以下语句来停用撤消表空间:

ALTER UNDO TABLESPACE tablespace_nameSET INACTIVE;

将撤消表空间标记为非活动后,允许完成当前在撤消表空间中使用回滚段的事务,以及在这些事务完成之前启动的任何事务。 事务完成后,清除系统释放撤消表空间中的回滚段,撤消表空间被截断为其初始大小,撤消表空间状态从更改 inactive empty

注意

语句停用撤消表空间时,清除线程会在下次机会时查找该撤消表空间。 找到撤消表空间并标记为截断后,清除线程将以更高的频率返回,以快速清空并截断撤消表空间。 ALTER UNDO TABLESPACE tablespace_name SET INACTIVE

要检查撤消表空间的状态,请查询该 INFORMATION_SCHEMA.INNODB_TABLESPACES 表。

SELECT NAME,STATE FROM INFORMATION_SCHEMA.INNODB_TABLESPACES 
  名称在哪里tablespace_name;

一旦撤消表空间处于某种 empty 状态,就可以通过发出以下语句来重新激活它:

ALTER UNDO TABLESPACE tablespace_nameSET ACTIVE;

empty 还可以删除状态中 的撤消表空间 请参阅 删除撤消表空间

加快撤消表空间的自动截断

清除线程负责清空和截断撤消表空间。 默认情况下,清除线程会查找撤消表空间,以便每调用一次清除128次就会截断一次。 清除线程查找撤消表空间以进行截断的频率由 innodb_purge_rseg_truncate_frequency 变量 控制,该 变量的默认设置为128。

MySQL的> SELECT @@innodb_purge_rseg_truncate_frequency;
+ ---------------------------------------- +
| @@ innodb_purge_rseg_truncate_frequency |
+ ---------------------------------------- +
| 128 |
+ ---------------------------------------- +

要增加该频率,请减小 innodb_purge_rseg_truncate_frequency 设置。 例如,要让purge线程每隔32个调用purge的时间一次查找undo tabespaces,设置 innodb_purge_rseg_truncate_frequency 为32。

MySQL的> SET GLOBAL innodb_purge_rseg_truncate_frequency=32;

当清除线程找到需要截断的撤消表空间时,清除线程以更高的频率返回,以快速清空并截断撤消表空间。

截断撤消表空间文件的性能影响

撤消撤消表空间时,撤消表空间中的回滚段将被停用。 其他撤消表空间中的活动回滚段承担整个系统负载的责任,这可能会导致性能略有下降。 性能下降的程度取决于许多因素:

  • 撤消表空间的数量

  • 撤消日志数

  • 撤消表空间大小

  • I / O susbsystem的速度

  • 现有的长期运行事务

  • 系统负载

截断撤消表空间时避免影响性能的最简单方法是增加撤消表空间的数量。

监视撤消表空间截断

在MySQL 8.0.16中, undo purge susbsystem计数器提供用于监视与撤销日志截断相关的后台活动。 对于计数器名称和描述,请查询该 INFORMATION_SCHEMA.INNODB_METRICS 表。

选择名称,子系统,来自INFORMATION_SCHEMA.INNODB_METRICS的评论,其中名称类似'%truncate%';

有关启用计数器和查询计数器数据的信息,请参见 第15.14.6节“InnoDB INFORMATION_SCHEMA度量表”

15.6.3.5临时表空间

InnoDB 使用会话临时表空间和全局临时表空间。

会话临时表空间

会话临时表空间存储由优化程序创建的用户创建的临时表和内部临时表,当 InnoDB 配置为磁盘内部临时表的存储引擎时。 从MySQL 8.0.16开始,始终使用用于磁盘内部临时表的存储引擎 InnoDB (以前,存储引擎是由值决定的 internal_tmp_disk_storage_engine 。)

会话临时表空间在第一个请求中从临时表空间池分配给会话,以创建磁盘上的临时表。 最多两个表空间分配给一个会话,一个用于用户创建的临时表,另一个用于由优化器创建的内部临时表。 分配给会话的临时表空间用于会话创建的所有磁盘上临时表。 会话断开连接时,其临时表空间将被截断并释放回池中。 启动服务器时,将创建一个包含10个临时表空间的池。 池的大小永远不会缩小,并且表空间会根据需要自动添加到池中。 临时表空间池在正常关闭或中止初始化时被删除。 会话临时表空间文件在创建时大小为五页,并且具有 .ibt 文件扩展名。

为会话临时表空间保留了40万个空间ID。 由于每次启动服务器时都会重新创建会话临时表空间池,因此当服务器关闭并且可以重用时,会话临时表空间的空间ID不会保留。

innodb_temp_tablespaces_dir 变量定义创建会话临时表空间的位置。 默认位置是 #innodb_temp 数据目录中的目录。 如果无法创建临时表空间池,则拒绝启动。

shell> cd BASEDIR/ data /#innodb_temp
shell> ls
temp_10.ibt temp_2.ibt temp_4.ibt temp_6.ibt temp_8.ibt
temp_1.ibt temp_3.ibt temp_5.ibt temp_7.ibt temp_9.ibt

在基于语句的复制(SBR)模式中,在从属服务器上创建的临时表驻留在单个会话临时表空间中,该表空间仅在MySQL服务器关闭时被截断。

INNODB_SESSION_TEMP_TABLESPACES 表提供有关会话临时表空间的元数据。

INFORMATION_SCHEMA.INNODB_TEMP_TABLE_INFO 表提供有关在 InnoDB 实例 中处于活动状态的用户创建的临时表的元数据

全局临时表空间

全局临时表空间( ibtmp1 )存储用于对用户创建的临时表所做更改的回滚段。

innodb_temp_data_file_path 变量定义全局临时表空间数据文件的相对路径,名称,大小和属性。 如果没有指定值 innodb_temp_data_file_path ,默认行为是创建一个名为一个自动扩展数据文件 ibtmp1 innodb_data_home_dir 目录。 初始文件大小略大于12MB。

在正常关闭或中止初始化时删除全局临时表空间,并在每次启动服务器时重新创建。 全局临时表空间在创建时会收到动态生成的空间ID。 如果无法创建全局临时表空间,则拒绝启动。 如果服务器意外停止,则不会删除全局临时表空间。 在这种情况下,数据库管理员可以手动删除全局临时表空间或重新启动MySQL服务器。 重新启动MySQL服务器会自动删除并重新创建全局临时表空间。

全局临时表空间不能驻留在原始设备上。

INFORMATION_SCHEMA.FILES 提供有关全局临时表空间的元数据。 发出类似于此查询的查询以查看全局临时表空间元数据:

MySQL的> SELECT * FROM INFORMATION_SCHEMA.FILES WHERE TABLESPACE_NAME='innodb_temporary'\G

默认情况下,全局临时表空间数据文件是自动扩展的,并根据需要增加大小。

要确定全局临时表空间数据文件是否自动扩展,请检查以下 innodb_temp_data_file_path 设置:

MySQL的> SELECT @@innodb_temp_data_file_path;
+ ------------------------------ +
| @@ innodb_temp_data_file_path |
+ ------------------------------ +
| ibtmp1:12M:autoextend |
+ ------------------------------ +

要检查全局临时表空间数据文件的大小,请 INFORMATION_SCHEMA.FILES 使用与此类似的查询来 查询 表:

MySQL的> SELECT FILE_NAME, TABLESPACE_NAME, ENGINE, INITIAL_SIZE, TOTAL_EXTENTS*EXTENT_SIZE 
       AS TotalSizeBytes, DATA_FREE, MAXIMUM_SIZE FROM INFORMATION_SCHEMA.FILES 
       WHERE TABLESPACE_NAME = 'innodb_temporary'\G
*************************** 1。排******************** *******
      FILE_NAME:./ ibtmp1
TABLESPACE_NAME:innodb_temporary
         ENGINE:InnoDB
   INITIAL_SIZE:12582912
 TotalSizeBytes:12582912
      DATA_FREE:6291456
   MAXIMUM_SIZE:NULL

TotalSizeBytes 显示全局临时表空间数据文件的当前大小。 有关其他字段值的信息,请参见 第25.11节“INFORMATION_SCHEMA文件表”

或者,检查操作系统上的全局临时表空间数据文件大小。 全局临时表空间数据文件位于由 innodb_temp_data_file_path 变量 定义的目录中

要回收全局临时表空间数据文件占用的磁盘空间,请重新启动MySQL服务器。 重新启动服务器将根据定义的属性删除并重新创建全局临时表空间数据文件 innodb_temp_data_file_path

要限制全局临时表空间数据文件的大小,请配置 innodb_temp_data_file_path 以指定最大文件大小。 例如:

的[mysqld]
innodb_temp_data_file_path = ibtmp1:12M:自动扩展:最大:500M

配置 innodb_temp_data_file_path 需要重新启动服务器。

15.6.3.6在数据目录之外创建表空间

CREATE TABLE ... DATA DIRECTORY 子句允许 在数据目录之外 创建 每表文件表 空间。 例如,您可以使用该 DATA DIRECTORY 子句在具有特定性能或容量特征的单独存储设备上创建表空间,例如快速 SSD 或高容量 HDD

确保您选择的位置。 DATA DIRECTORY 子句不能用于 ALTER TABLE 以后更改位置。

表空间数据文件在指定目录中创建,该目录位于为表所属的模式命名的子目录中。

以下示例演示如何在数据目录之外创建每个表的文件表空间。 假设 innodb_file_per_table 变量已启用。

MySQL的> USE test;
数据库已更改

MySQL的> CREATE TABLE t1 (c1 INT PRIMARY KEY) DATA DIRECTORY = '/remote/directory';

#MySQL在名为的子目录中创建表空间文件
#表示表所属的模式

shell> cd /remote/directory/test
shell>ls
t1.ibd

在数据目录之外创建表空间时,请确保已知该目录 InnoDB 否则,如果服务器在完全刷新表空间数据文件页面之前意外暂停,则在检索已知目录中的表空间数据文件的恢复前发现阶段未找到表空间时启动失败(请参阅 崩溃恢复期间的表空间发现 )。 要使目录已知,请将其添加到 innodb_directories 参数值。 innodb_directories 是一个只读启动选项,用于定义在启动时扫描表空间数据文件的目录。 配置它需要重新启动服务器。

CREATE TABLE ... TABLESPACE 语法也可以与 DATA DIRECTORY 子句 结合使用, 以在数据目录之外创建每表文件表空间。 为此,请指定 innodb_file_per_table 为表空间名称。

MySQL的> CREATE TABLE t2 (c1 INT PRIMARY KEY) TABLESPACE = innodb_file_per_table
       DATA DIRECTORY = '/remote/directory';

innodb_file_per_table 使用此方法时,不需要启用 变量。

使用说明:
  • MySQL最初将表空间数据文件保持打开状态,阻止您卸载设备,但如果服务器繁忙,最终可能会关闭表。 小心不要在MySQL运行时意外卸载外部设备,或在设备断开连接时启动MySQL。 在关联的表空间数据文件丢失时尝试访问表会导致严重错误,需要重新启动服务器。

    如果表空间数据文件不在预期路径,则服务器重新启动会发出错误和警告。 在这种情况下,您可以从备份还原表空间数据文件,或删除表以从 数据字典中 删除有关它的 信息

  • 在将表空间放在已安装NFS的卷上之前,请查看 使用NFS与MySQL中 列出的潜在问题

  • 如果使用LVM快照,文件副本或其他基于文件的机制来备份表空间数据文件,请始终 FLUSH TABLES ... FOR EXPORT 首先 使用该 语句,以确保 在备份发生之前将 内存中缓冲的所有更改 刷新 到磁盘。

  • 使用该 DATA DIRECTORY 子句是 使用符号链接 的替代 方法 ,这是不受支持的。

15.6.3.7将表空间复制到另一个实例

本节介绍如何将 每个表 文件表 空间从一个MySQL实例 复制 到另一个MySQL实例,也称为可 传输表空间 功能。 此功能还支持分区 InnoDB 表和单个 InnoDB 表分区和子分区。

有关其他 InnoDB 表复制方法的信息,请参见 第15.6.1.2节“移动或复制InnoDB表”

InnoDB 每个表文件表 空间 复制 到另一个实例的 原因有很多

  • 在不对生产服务器施加额外负载的情况下运行报告。

  • 在新的 从属服务器 上为表设置相同的数据

  • 在出现问题或错误后还原表或分区的备份版本。

  • 作为一种更快速的数据移动方式,比导入 mysqldump 命令 的结果更快 数据立即可用,而不必重新插入并重建索引。

  • 每个表 文件表 空间移动到具有更适合系统要求的存储介质的服务器。 例如,您可能希望在 SSD 设备 上使用忙表 ,或在高容量 HDD 设备 上使用大表

限制和使用说明
  • 只有在 innodb_file_per_table 启用 时才能使用表空间复制过程 ,这是默认设置。 驻留在共享系统表空间中的表无法停顿。

  • 当表静默时,受影响的表上只允许只读事务。

  • 导入表空间时,页面大小必须与导入实例的页面大小匹配。

  • ALTER TABLE ... DISCARD TABLESPACE 分区 InnoDB ALTER TABLE ... DISCARD PARTITION ... TABLESPACE 支持, InnoDB 表分区 支持

  • DISCARD TABLESPACE 不支持与父子时(主键-外键)关系表空间 foreign_key_checks 设置为 1 在丢弃父子表的表空间之前,请设置 foreign_key_checks=0 分区 InnoDB 表不支持外键。

  • ALTER TABLE ... IMPORT TABLESPACE 不会对导入的数据强制执行外键约束。 如果表之间存在外键约束,则应在相同(逻辑)时间点导出所有表。 分区 InnoDB 表不支持外键。

  • ALTER TABLE ... IMPORT TABLESPACE 并且 ALTER TABLE ... IMPORT PARTITION ... TABLESPACE 不需要 .cfg 元数据文件来导入表空间。 但是,在没有 .cfg 文件 导入时不执行元数据检查 ,并发出类似于以下的警告:

    消息:InnoDB:IO读取错误:(2,没有这样的文件或目录)错误打开'。\
    test \ t.cfg'将尝试导入而不进行模式验证
    1排(0.00秒)
    

    .cfg 当没有预期的模式不匹配时,没有文件 导入的能力 可能更方便。 此外,在没有 .cfg 文件的情况下 导入的 功能在崩溃恢复方案中非常有用,在这种情况下无法从 .ibd 文件中 收集元数据

    如果未 .cfg 使用 任何 文件,则 InnoDB 使用等效的 语句来初始化用于为 分配值的内存中自动增量计数器 否则,从 元数据文件中 读取当前最大自动增量计数器值 有关相关信息,请参阅 InnoDB AUTO_INCREMENT计数器初始化 SELECT MAX(ai_col) FROM table_name FOR UPDATE AUTO_INCREMENT .cfg

  • 由于 .cfg 元数据文件限制,在导入分区表的表空间文件时,不会报告分区类型或分区定义差异的模式不匹配。 报告了列差异。

  • 运行 ALTER TABLE ... DISCARD PARTITION ... TABLESPACE ALTER TABLE ... IMPORT PARTITION ... TABLESPACE 在子分区表上时,允许分区和子分区表名称。 指定分区名称时,该分区的子分区将包含在操作中。

  • 如果两个实例都具有GA(一般可用性)状态,并且导入文件的服务器实例在同一版本系列中处于相同或更高版本级别,则从另一个MySQL服务器实例导入表空间文件。 不支持将表空间文件导入到运行早期版本的MySQL的服务器实例中。

  • 在复制方案中, innodb_file_per_table 必须 ON 在主服务器和从服务器上都 设置为

  • 在Windows上, InnoDB 内部以小写形式存储数据库,表空间和表名。 为避免在区分大小写的操作系统(如Linux和UNIX)上导入问题,请使用小写名称创建所有数据库,表空间和表。 完成此操作的一种便捷方法是 在创建数据库,表空间或表之前将以 下行添加到 文件 [mysqld] 部分 my.cnf my.ini

    的[mysqld]
    的lower_case_table_names = 1
    
    注意

    禁止 lower_case_table_names 使用与初始化 服务器时使用的 设置不同的设置启动服务器。

  • ALTER TABLE ... DISCARD TABLESPACE 并且 ALTER TABLE ...IMPORT TABLESPACE 不支持属于 InnoDB 常规表空间的表。 有关更多信息,请参阅 CREATE TABLESPACE

  • InnoDB 的默认行格式 可使用 innodb_default_row_format 配置选项 进行 配置。 如果 源实例上的设置与目标实例上的设置不同,则 尝试导入未显式定义行format( ROW_FORMAT )或使用的表 ROW_FORMAT=DEFAULT 可能导致模式不匹配错误 innodb_default_row_format 有关相关信息,请参阅 定义表的行格式

  • 导出加密表空间时, 除了 元数据文件 外,还会 InnoDB 生成 文件。 对目标实例 执行 操作 之前, 必须将 文件与文件和表空间文件 一起复制到 目标实例。 文件包含传输密钥和加密的表空间密钥。 在导入时, 使用传输密钥来解密表空间密钥。 有关相关信息,请参见 第15.6.3.9节“InnoDB静态数据加密” .cfp .cfg .cfp .cfg ALTER TABLE ... IMPORT TABLESPACE .cfp InnoDB

  • FLUSH TABLES ... FOR EXPORT 具有FULLTEXT索引的表不受支持。 不刷新全文搜索辅助表。 导入带 FULLTEXT 索引 的表后 ,运行 OPTIMIZE TABLE 以重建 FULLTEXT 索引。 或者, FULLTEXT 在导出操作之前 删除 索引,并在导入目标实例上的表后重新创建它们。

15.6.3.7.1可传输表空间示例
注意

如果要传输使用 InnoDB 表空间加密 进行加密的 表,请 在开始获取其他过程信息之前 参阅 限制和使用说明

示例1:将InnoDB表复制到另一个实例

此过程演示如何将常规 InnoDB 表从正在运行的MySQL服务器实例 复制 到另一个正在运行的实例。 可以使用具有微小调整的相同过程在同一实例上执行完整表还原。

  1. 在源实例上,创建一个表(如果不存在):

    mysql> USE test;
    mysql>CREATE TABLE t(c1 INT) ENGINE=InnoDB;
    
  2. 在目标实例上,创建一个表(如果不存在):

    mysql> USE test;
    mysql>CREATE TABLE t(c1 INT) ENGINE=InnoDB;
    
  3. 在目标实例上,放弃现有表空间。 (在导入表空间之前, InnoDB 必须丢弃附加到接收表的表空间。)

    MySQL的> ALTER TABLE t DISCARD TABLESPACE;
    
  4. 在源实例上,运行 FLUSH TABLES ... FOR EXPORT 以停顿表并创建 .cfg 元数据文件:

    mysql> USE test;
    mysql>FLUSH TABLES t FOR EXPORT;
    

    metadata( .cfg )在 InnoDB 数据目录中 创建

    注意

    FLUSH TABLES ... FOR EXPORT 语句确保已将对指定表的更改刷新到磁盘,以便在实例运行时可以生成二进制表副本。 FLUSH TABLES ... FOR EXPORT 运行时, InnoDB 产生了 .cfg 在同一个数据库的目录表文件。 .cfg 文件包含导入表空间文件时用于模式验证的元数据。

  5. .ibd 文件和 .cfg 元数据文件从源实例 复制 到目标实例。 例如:

    外壳> scp /path/to/datadir/test/t.{ibd,cfg} destination-server:/path/to/datadir/test
    
    注意

    .ibd 文件和 .cfg 文件必须释放共享锁之前如在下一步中所述被复制。

  6. 在源实例上,用于 UNLOCK TABLES 释放通过 FLUSH TABLES ... FOR EXPORT 以下方式 获取的锁

    mysql> USE test;
    mysql>UNLOCK TABLES;
    
  7. 在目标实例上,导入表空间:

    mysql> USE test;
    mysql>ALTER TABLE t IMPORT TABLESPACE;
    
    注意

    ALTER TABLE ... IMPORT TABLESPACE 功能不会对导入的数据强制执行外键约束。 如果表之间存在外键约束,则应在相同(逻辑)时间点导出所有表。 在这种情况下,您将停止更新表,提交所有事务,获取表上的共享锁,然后执行导出操作。

示例2:将InnoDB分区表复制到另一个实例

此过程演示如何将分区 InnoDB 表从正在运行的MySQL服务器实例 复制 到另一个正在运行的实例。 可以使用具有微小调整的相同过程 InnoDB 在同一实例上 执行分区 的完全还原

  1. 在源实例上,创建分区表(如果不存在)。 在以下示例中,将创建一个包含三个分区(p0,p1,p2)的表:

    mysql> USE test;
    mysql>CREATE TABLE t1 (i int) ENGINE = InnoDB PARTITION BY KEY (i) PARTITIONS 3;
    

    目录中, 三个分区中的每个分区 都有一个单独的tablespace( )文件。 /datadir/test .ibd

    MySQL的> \! ls /path/to/datadir/test/
    t1#P#p0.ibd t1#P#p1.ibd t1#P#p2.ibd
    
  2. 在目标实例上,创建相同的分区表:

    mysql> USE test;
    mysql>CREATE TABLE t1 (i int) ENGINE = InnoDB PARTITION BY KEY (i) PARTITIONS 3;
    

    目录中, 三个分区中的每个分区 都有一个单独的tablespace( )文件。 /datadir/test .ibd

    MySQL的> \! ls /path/to/datadir/test/
    t1#P#p0.ibd t1#P#p1.ibd t1#P#p2.ibd
    
  3. 在目标实例上,丢弃分区表的表空间。 (在可以在目标实例上导入表空间之前,必须丢弃附加到接收表的表空间。)

    MySQL的> ALTER TABLE t1 DISCARD TABLESPACE;
    

    .ibd 组成分区表的表空间 的三个 文件将从 目录 中丢弃 /datadir/test

  4. 在源实例上,运行 FLUSH TABLES ... FOR EXPORT 以停顿分区表并创建 .cfg 元数据文件:

    mysql> USE test;
    mysql>FLUSH TABLES t1 FOR EXPORT;
    

    在源实例 目录 中创建 Metadata( .cfg )文件,每个tablespace( .ibd )文件 一个 文件 /datadir/test

    MySQL的> \! ls /path/to/datadir/test/
    t1#P#p0.ibd t1#P#p1.ibd t1#P#p2.ibd
    t1#P#p0.cfg t1#P#p1.cfg t1#P#p2.cfg
    
    注意

    FLUSH TABLES ... FOR EXPORT 语句确保已将对指定表的更改刷新到磁盘,以便在实例运行时进行二进制表复制。 FLUSH TABLES ... FOR EXPORT 运行时, InnoDB 产生 .cfg 在同一数据库的目录表中的表的表空间文件元数据文件。 这些 .cfg 文件包含导入表空间文件时用于模式验证的元数据。 FLUSH TABLES ... FOR EXPORT 只能在表上运行,而不能在单个表分区上运行。

  5. .ibd .cfg 实例数据库目录中 文件 复制 到目标实例数据库目录。 例如:

    壳> SCP /path/to/datadir/test/t1*.{ibd,cfg} destination-server:/path/to/datadir/test
    
    注意

    .ibd .cfg 文件必须释放共享锁之前如在下一步中所述被复制。

  6. 在源实例上,用于 UNLOCK TABLES 释放通过 FLUSH TABLES ... FOR EXPORT 以下方式 获取的锁

    mysql> USE test;
    mysql>UNLOCK TABLES;
    
  7. 在目标实例上,导入分区表的表空间:

    mysql> USE test;
    mysql>ALTER TABLE t1 IMPORT TABLESPACE;
    
示例3:将InnoDB表分区复制到另一个实例

此过程演示如何将 InnoDB 表分区从正在运行的MySQL服务器实例 复制 到另一个正在运行的实例。 可以使用具有微小调整的相同过程 InnoDB 在同一实例上 执行 表分区 的还原 在以下示例中,将在源实例上创建具有四个分区(p0,p1,p2,p3)的分区表。 其中两个分区(p2和p3)被复制到目标实例。

  1. 在源实例上,创建分区表(如果不存在)。 在以下示例中,将创建一个包含四个分区(p0,p1,p2,p3)的表:

    mysql> USE test;
    mysql>CREATE TABLE t1 (i int) ENGINE = InnoDB PARTITION BY KEY (i) PARTITIONS 4;
    

    目录中, 四个分区中的每个分区 都有一个单独的tablespace( )文件。 /datadir/test .ibd

    MySQL的> \! ls /path/to/datadir/test/
    t1#P#p0.ibd t1#P#p1.ibd t1#P#p2.ibd t1#P#p3.ibd
    
  2. 在目标实例上,创建相同的分区表:

    mysql> USE test;
    mysql>CREATE TABLE t1 (i int) ENGINE = InnoDB PARTITION BY KEY (i) PARTITIONS 4;
    

    目录中, 四个分区中的每个分区 都有一个单独的tablespace( )文件。 /datadir/test .ibd

    MySQL的> \! ls /path/to/datadir/test/
    t1#P#p0.ibd t1#P#p1.ibd t1#P#p2.ibd t1#P#p3.ibd
    
  3. 在目标实例上,丢弃计划从源实例导入的表空间分区。 (可以在目标实例上导入表空间分区之前,必须丢弃附加到接收表的相应分区。)

    MySQL的> ALTER TABLE t1 DISCARD PARTITION p2, p3 TABLESPACE;
    

    .ibd 目标实例上的目录 中删除两个丢弃的分区 文件 ,留下以下文件: /datadir/test

    MySQL的> \! ls /path/to/datadir/test/
    t1#P#p0.ibd t1#P#p1.ibd
    
    注意

    ALTER TABLE ... DISCARD PARTITION ... TABLESPACE 上subpartitioned表上运行,无论分区和子分区表名是允许的。 指定分区名称时,该分区的子分区将包含在操作中。

  4. 在源实例上,运行 FLUSH TABLES ... FOR EXPORT 以停顿分区表并创建 .cfg 元数据文件。

    mysql> USE test;
    mysql>FLUSH TABLES t1 FOR EXPORT;
    

    元数据文件( .cfg 文件) 在源实例 目录 中创建 有一个 为每个表空间(文件 )文件。 /datadir/test .cfg .ibd

    MySQL的> \! ls /path/to/datadir/test/
    t1#P#p0.ibd t1#P#p1.ibd t1#P#p2.ibd t1#P#p3.ibd
    t1#P#p0.cfg t1#P#p1.cfg t1#P#p2.cfg t1#P#p3.cfg
    
    注意

    FLUSH TABLES ... FOR EXPORT 语句确保已将对指定表的更改刷新到磁盘,以便在实例运行时进行二进制表复制。 FLUSH TABLES ... FOR EXPORT 运行时, InnoDB 产生 .cfg 在同一数据库的目录表中的表的表空间文件元数据文件。 这些 .cfg 文件包含导入表空间文件时用于模式验证的元数据。 FLUSH TABLES ... FOR EXPORT 只能在表上运行,而不能在单个表分区上运行。

  5. .ibd .cfg 实例数据库目录中 文件 复制 到目标实例数据库目录。 在此示例中,仅将 分区2(p2)和分区3(p3) .ibd .cfg 文件复制到 data 目标实例上的目录。 分区0(p0)和分区1(p1)保留在源实例上。

    外壳> scp t1#P#p2.ibd  t1#P#p2.cfg t1#P#p3.ibd t1#P#p3.cfg destination-server:/path/to/datadir/test
    
    注意

    .ibd 文件和 .cfg 文件必须释放共享锁之前如在下一步中所述被复制。

  6. 在源实例上,用于 UNLOCK TABLES 释放通过 FLUSH TABLES ... FOR EXPORT 以下方式 获取的锁

    mysql> USE test;
    mysql>UNLOCK TABLES;
    
  7. 在目标实例上,导入表空间分区(p2和p3):

    mysql> USE test;
    mysql>ALTER TABLE t1 IMPORT PARTITION p2, p3 TABLESPACE;
    
    注意

    ALTER TABLE ... IMPORT PARTITION ... TABLESPACE 上subpartitioned表上运行,无论分区和子分区表名是允许的。 指定分区名称时,该分区的子分区将包含在操作中。

15.6.3.7.2可移动表空间内部

以下信息描述了常规 InnoDB 的可传输表空间复制过程的内部和错误日志消息传递

何时 ALTER TABLE ... DISCARD TABLESPACE 在目标实例上运行:

  • 该表被锁定在X模式下。

  • 表空间与表分离。

何时 FLUSH TABLES ... FOR EXPORT 在源实例上运行:

  • 刷新导出的表在共享模式下被锁定。

  • 清除协调器线程已停止。

  • 脏页面与磁盘同步。

  • 表元数据被写入二进制 .cfg 文件。

此操作的预期错误日志消息:

2013-09-24T13:10:19.903526Z 2 [注意] InnoDB:与“test”同步到磁盘。“t”'开始了。
2013-09-24T13:10:19.903586Z 2 [注意] InnoDB:停止清除
2013-09-24T13:10:19.903725Z 2 [注意] InnoDB:将表格元数据写入'./test/t.cfg'
2013-09-24T13:10:19.904014Z 2 [注意] InnoDB:表'“test”。“t”'刷新到磁盘
 

何时 UNLOCK TABLES 在源实例上运行:

  • 二进制.cfg文件已删除。

  • 将导入要导入的表上的共享锁,并重新启动清除协调程序线程。

此操作的预期错误日志消息:

2013-09-24T13:10:21.181104Z 2 [注意] InnoDB:删除元数据文件'./test/t.cfg'
2013-09-24T13:10:21.181180Z 2 [注意] InnoDB:恢复清除

ALTER TABLE ... IMPORT TABLESPACE 目标实例上运行时,导入算法会为要导入的每个表空间执行以下操作:

  • 检查每个表空间页面是否损坏。

  • 每页上的空间ID和日志序列号(LSN)都会更新

  • 验证标志并更新标题页的LSN。

  • Btree页面已更新。

  • 页面状态设置为脏,以便将其写入磁盘。

此操作的预期错误日志消息:

2013-07-18 15:15:01 34960 [注意] InnoDB:导入从主机'ubuntu'导出的表'test / t'的表空间
2013-07-18 15:15:01 34960 [注意] InnoDB:第一阶段 - 更新所有页面
2013-07-18 15:15:01 34960 [注意] InnoDB:同步到磁盘
2013-07-18 15:15:01 34960 [注意] InnoDB:同步到磁盘 - 完成!
2013-07-18 15:15:01 34960 [注意] InnoDB:第三阶段 - 刷新磁盘更改
2013-07-18 15:15:01 34960 [注意] InnoDB:第四阶段 - 冲洗完成
注意

您可能还会收到一个警告,表示已丢弃表空间(如果您丢弃了目标表的表空间),并且收到一条消息,指出由于缺少 .ibd 文件 而无法计算统计信息

2013-07-18 15:14:38 34960 [警告] InnoDB:表“test”。“t”表空间被设置为丢弃。
2013-07-18 15:14:38 7f34d9a37700 InnoDB:无法计算表“test”的统计数据。“t” 
因为缺少.ibd文件。如需帮助,请参阅
http://dev.mysql.com/doc/refman/8.0/en/innodb-troubleshooting.html

15.6.3.8服务器脱机时移动表空间文件

innodb_directories 选项定义了在启动时扫描表空间文件的目录,支持在服务器脱机时将表空间文件移动或恢复到新位置。 在启动期间,使用发现的表空间文件而不是数据字典中引用的那些文件,并更新数据字典以引用重定位的文件。 如果扫描发现重复的表空间文件,则启动失败,并显示错误,指示为同一表空间ID找到了多个文件。

由定义的目录 innodb_data_home_dir innodb_undo_directory datadir 配置选项自动附加到 innodb_directories 参数值。 无论是否 innodb_directories 明确指定选项, 都会在启动时扫描这些目录 隐式添加这些目录允许移动系统表空间文件,数据目录或撤消表空间文件,而无需配置 innodb_directories 设置。 但是,目录更改时必须更新设置。 例如,重定位数据目录后,必须