MySQL InnoDB与联机DDL

InnoDB与联机DDL
InnoDB联机DDL特性允许就地表更改或并发DML,或两者兼而有之。这个特性的好处包括:
.改进了繁忙的生产环境中的响应性和可用性,在这些环境中,使表在几分钟或几小时内不可用是不现实的。

.使用LOCK子句在DDL操作期间调整性能和并发性之间的平衡的能力。
.LOCK=EXCLUSIVE完全阻塞对表的访问

.LOCK=SHARED允许查询,但不允许DML。

.LOCK=NONE允许对表进行完整的查询和DML访问。

.LOCK=DEFAULT或省略LOCK子句允许尽可能多的并发,具体取决于DDL操作的类型。

.避免了与复制表和重建二级索引相关的磁盘空间使用和I/O开销。

联机DDL概述
联机DDL特性增强了许多DDL操作,这些操作以前需要表复制或阻塞表上的DML操作,或者两者兼而有之。除了大多数ALTER TABLE分区子句之外,分区后的InnoDB表的在线DDL操作遵循与普通InnoDB表相同的规则。一些因素会影响在线DDL操作的性能、空间使用和语义。
.”In-Place?”列显示哪些操作允许使用ALGORITHM=INPLACE子句。

.”Rebuilds Table?”列显示重建表的操作。对于使用INPLACE算法的操作,将就地重建表。对于不支持INPLACE算法的操作,使用表复制方法重建表。

.”Permits Concurrent DML?”列显示哪些操作是完全在线执行的。您可以指定LOCK=NONE来断言在DDL操作期间允许并发DML。MySQL在可能的情况下自动允许并发DML。

在所有在线DDL操作期间都允许并发查询。可以指定LOCK=SHARED来断言在DDL操作期间允许并发查询。MySQL在可能的情况下自动允许并发查询。

.“Notes”列提供额外的信息,并解释与其他列的“Yes/No”值相关的异常和依赖关系。星号表示异常或依赖。

下面的小节提供了各种在线DDL操作的基本语法和用法说明。
添加或删除二级索引
.添加二级索引:

CREATE INDEX name ON table (col_list);

ALTER TABLE table ADD INDEX name (col_list);

.删除二级索引:

DROP INDEX name ON table;

ALTER TABLE table DROP INDEX name;

尽管在CREATE INDEX或DROP INDEX命令中不需要更改语法,但有一些因素会影响此操作的性能、空间使用和语义。

在InnoDB表上创建和删除二级索引会跳过表复制行为。

在创建或删除索引时,表仍然可用于读写操作。CREATE INDEX或DROP INDEX语句仅在所有访问表的事务完成后才完成,因此索引的初始状态反映了表的最新内容。以前,在创建或删除索引时修改表通常会导致死锁,从而取消表上的INSERT、UPDATE或DELETE语句。

在线DDL支持添加二级索引,这意味着通常可以加快创建和加载表及其关联索引的整体过程,方法是创建不带任何二级索引的表,然后在加载数据后添加二级索引。

修改列属性
.修改列的默认值:

ALTER TABLE tbl ALTER COLUMN col SET DEFAULT literal;
ALTER TABLE tbl ALTER COLUMN col DROP DEFAULT;

列的默认值存储在表的.frm文件中,而不是InnoDB数据字典中。

.更改列的自动增量值:
ALTER TABLE table AUTO_INCREMENT=next_value;

特别是在使用复制或分片的分布式系统中,有时需要将表的自动递增计数器重置为特定值。插入到表中的下一行使用指定的值作为其自动递增列。您也可以在数据仓库环境中使用此技术,您可以定期清空所有表并重新加载它们,并且可以从1重新启动自动递增序列。

.重命名列
ALTER TABLE tbl CHANGE old_col_name new_col_name datatype;

当您保持相同的数据类型和[NOT] NULL属性时,仅更改列名,此操作始终可以在线执行。

还可以重命名属于外键约束的列。外键定义会自动更新,以使用新的列名。重命名参与外键的列仅适用于ALTER TABLE的in-place模式。如果使用了ALGORITHM=COPY子句,或者其他条件导致命令在后台使用了ALGORITHM=COPY,那么ALTER TABLE语句就会失败。

.使用in-place ALTER TABLE语句扩展VARCHAR的大小:
ALTER TABLE t13 ALGORITHM=INPLACE, CHANGE COLUMN c1 c1 VARCHAR(50);

VARCHAR列所需的长度字节数必须保持不变。对于0到255的VARCHAR值,需要一个长度字节来编码该值。对于256字节或更多的VARCHAR值,需要两个长度字节。因此,in-place ALTER TABLE只支持将VARCHAR大小从0增加到255字节,或将VARCHAR大小从等于或大于256字节的值增加。In-place ALTER TABLE不支持将VARCHAR大小从小于256字节增加到等于或大于256字节。在这种情况下,所需长度字节的数量将从1变为2,只有表复制(ALGORITHM= copy)才支持这种情况。例如,试图使用in-place ALTER TABLE将VARCHAR列的大小从255更改为256将会返回错误:

mysql> ALTER TABLE t13 ALGORITHM=INPLACE, CHANGE COLUMN c1 c1 VARCHAR(256);
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.

mysql> ALTER TABLE t13 ALGORITHM=COPY, CHANGE COLUMN c1 c1 VARCHAR(256);
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

不支持使用in-place ALTER TABLE减少VARCHAR大小。减少VARCHAR的大小需要表的复制(ALGORITHM=COPY)。

mysql> ALTER TABLE t13 ALGORITHM=INPLACE, CHANGE COLUMN c1 c1 VARCHAR(20);
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.

mysql> ALTER TABLE t13 ALGORITHM=COPY, CHANGE COLUMN c1 c1 VARCHAR(20);
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

添加或删除外键
.添加或删除外键约束:

ALTER TABLE tbl1 ADD CONSTRAINT fk_name FOREIGN KEY index (col1) REFERENCES tbl2(col2) referential_actions;

ALTER TABLE tbl DROP FOREIGN KEY fk_name;

删除外键可以在启用或禁用foreign_key_checks选项的情况下在线执行。在线创建外键需要禁用foreign_key_checks。

如果你不知道某张表上的外键约束的名称,执行下面的语句,并在每个外键的约束子句中找到约束名称:

SHOW CREATE TABLE table\G

或者,查询INFORMATION_SCHEMA.TABLE_CONSTRAINTS表,使用CONSTRAINT_NAME和CONSTRAINT_TYPE列来标识外键的名称。

你也可以在一条语句中删除外键及其关联索引:

ALTER TABLE table DROP FOREIGN KEY constraint, DROP INDEX index;

如果外键已经存在于被修改的表中(也就是说,它是一个包含FOREIGN KEY …REFERENCE子句的子表),其他的限制适用于在线DDL操作,即使是那些不直接涉及外键列的操作:

.如果对父表的更改通过使用CASCADE或SET NULL参数的on UPDATE或on DELETE子句引起子表的相关更改,则子表上的ALTER TABLE可以等待另一个事务提交。

.同样,如果一张表是外键关系中的父表,即使它不包含任何外键子句,如果INSERT、UPDATE或DELETE语句导致子表中的ON UPDATE或ON DELETE操作,它也可以等待ALTER TABLE完成。

维护CREATE TABLE语句
当你的数据库模式随着新列、数据类型、约束、索引等的变化而变化时,请确保CREATE TABLE语句与最新的表定义保持一致。即使有了在线DDL的性能改进,在开始时创建稳定的数据库结构比创建模式的一部分然后发出ALTER TABLE语句更有效。

对有大量行记录表的二级索引这条准则除外。通常最有效的做法是:先指定除二级索引之外的所有详细信息,然后加载数据,再创建二级索引。如果您知道初始数据是干净的,并且在加载过程中不需要一致性检查,则可以对外键使用相同的技术(首先加载数据,然后设置外键)。

无论CREATE TABLE、CREATE INDEX、ALTER TABLE和类似的语句是如何将一个表组合在一起的,您都可以通过执行语句SHOW CREATE TABLE TABLE \G(为了整洁的格式化,需要大写\G)来捕获重建表所需的SQL。上述输出显示了numeric precision、NOT NULL和CHARACTER SET等子句,这些子句有时是在后台添加的,用户可能希望在新系统上克隆表或设置相同类型的外键列时省去这些子句。

联机DDL性能、并发性和空间需求
联机DDL提高了MySQL操作的几个方面,如性能、并发性、可用性和可伸缩性:
.由于表上的查询和DML操作可以在DDL进行时继续进行,因此访问表的应用程序响应更快。在整个MySQL服务器中减少锁和等待其他资源会带来更大的可伸缩性,即使对于不涉及修改表的操作也是如此。

.对于in-place操作,通过避免重新构建表所需的磁盘I/O和CPU周期,可以最小化数据库的总体负载,并在DDL操作期间保持良好的性能和高吞吐量。

.对于in-place操作,由于读入缓冲池的数据比复制所有数据要少,因此可以避免从内存中清除频繁访问的数据,这在以前可能会在DDL操作之后导致暂时的性能下降。

如果联机操作需要临时排序文件,InnoDB默认在临时文件目录下创建它们,而不是在包含原始表的目录下。如果这个目录不够大,无法容纳这样的文件,您可能需要将tmpdir系统变量设置为另一个目录。另外,您可以使用innodb_tmpdir配置选项为InnoDB在线ALTER TABLE操作定义一个单独的临时目录。

联机DDL的锁选项
当DDL操作改变InnoDB表时,表可能被锁住,也可能不被锁住,这取决于DDL操作的内部工作原理和ALTER table语句的LOCK子句。默认情况下,MySQL在DDL操作期间使用尽可能少的锁;您可以指定这个子句,使锁定比通常情况下更加严格(从而限制并发DML或DML和查询),或者确保某个操作允许某种预期程度的锁定。如果LOCK子句指定的锁级别不适用于特定类型的DDL操作,例如在创建或删除主键时指定LOCK=SHARED或LOCK=NONE,那么该子句就会像断言一样工作,导致语句失败并报错。下面列出了LOCK子句的不同可能性,从最宽松的到最严格的:

.对于LOCK=NONE的DDL操作,查询和并发DML都是允许的。如果不能使用所请求的锁类型执行DDL操作,则该子句会使ALTER TABLE失败,因此,如果保持表完全可用是至关重要的,则指定LOCK=NONE,如果不可能则可以取消DDL。例如,您可以在DDLs中对涉及客户注册或购买的表使用此子句,以避免错误地发出昂贵的ALTER TABLE语句,从而使这些表不可用。

.对于LOCK=SHARED的DDL操作,任何对表的写操作(即DML操作)都会被阻塞,但是可以读取表中的数据。如果请求的锁类型不能执行这种DDL操作,则该子句会使ALTER TABLE失败,因此,如果保持表对查询可用非常重要,则指定LOCK=SHARED,如果不可能,则可以取消DDL。例如,您可以在DDL中为数据仓库中的表使用这个子句,在DDL中可以延迟数据加载操作直到DDL完成,但是不能长时间延迟查询。

.对于使用LOCK=DEFAULT或省略LOCK子句的DDL操作,MySQL针对此类操作使用可用的最低级别的锁,允许并发查询、DML或两者同时使用。当您根据表的工作负载进行预先计划、预先测试的更改,并且知道不会导致任何可用性问题时,将使用此设置。

.对于LOCK=EXCLUSIVE的DDL操作,查询和DML操作都被阻塞。如果请求的锁类型不能执行这种DDL操作,这个子句会使ALTER TABLE失败,因此,如果主要关注的是在尽可能短的时间内完成DDL,则指定LOCK=EXCLUSIVE,并且可以使应用程序在尝试访问表时等待。如果服务器应该是空闲的,您也可以使用LOCK=EXCLUSIVE,以避免对表的意外访问。

在大多数情况下,表上的联机DDL操作等待正在访问表的当前执行的事务提交或回滚,因为在准备DDL语句时,它需要在短时间内独占访问表。同样,联机DDL操作在完成之前需要对表进行短时间的独占访问。因此,联机DDL语句也会等待DDL正在提交或回滚时启动的事务完成。因此,对于执行插入、更新、删除的长时间运行的事务或对表执行SELECT .. FOR UPDATE操作,联机DDL操作可能会超时等待对表的独占访问。

当表处于外键关系中,并且事务在外键关系中的另一个表上显式运行时,可能发生表上的在线DDL操作不等待当前执行的事务完成的情况。在这种情况下,事务在它正在更新的表上持有一个排他的元数据锁,但只持有另一张表上共享的InnoDB表锁(外键检查所需)。共享的InnoDB表锁允许在线DDL操作继续进行,当需要一个互斥的InnoDB表锁时会在提交阶段阻塞操作。当其他事务等待在线DDL操作提交时,此场景可能导致死锁。(参见Bug #48652和Bug #77390)

因为需要一些处理工作来记录并发DML操作所做的更改,然后在最后应用这些更改,所以在线DDL操作可能比阻止其他会话访问表的旧式机制花费更长的时间。原始性能的降低与使用表的应用程序更好的响应性是平衡的。在评估更改表结构的理想技术时,要根据诸如网页加载时间等因素,考虑最终用户对性能的感知。

当CREATE INDEX或ALTER TABLE语句执行完毕时,一个新创建的InnoDB二级索引只包含表中已提交的数据。它不包含任何未提交的值、值的旧版本或标记为删除但尚未从旧索引中删除的值。

In-PlaceDDL操作与Table-Copy DDL操作的性能
在线DDL操作的原始性能在很大程度上取决于该操作是in-place执行,还是需要复制和重建整个表。

in-place DDL带来的性能提升适用于二级索引上的操作,而不是主键索引。InnoDB表中的行存储在一个基于主键组织的聚集索引中,形成了一些数据库系统所称的“索引组织表”。因为表结构与主键紧密联系在一起,所以重新定义主键仍然需要复制数据。

当对主键的操作使用ALGORITHM=INPLACE时,即使数据仍然被复制,它也比使用ALGORITHM=COPY更有效,因为:
.ALGORITHM=INPLACE不需要undo日志记录或相关的重做日志记录。这些操作增加了使用ALGORITHM=COPY的DDL语句的开销。

.二级索引项是预先排序的,因此可以按顺序加载。

.没有使用更改缓冲区,因为没有随机访问插入到二级索引中。

为了判断在线DDL操作的相对性能,你可以使用当前版本和更早版本的MySQL在一个大的InnoDB表上运行这样的操作。还可以在最新的MySQL版本下运行所有性能测试,通过设置old_alter_table系统变量,模拟“before”结果的DDL行为。在会话中发出语句set old_alter_table=1,并测量DDL性能以记录“之前”的数字。然后设置old_alter_table=0以重新启用更新、更快的行为,并再次运行DDL操作以记录“之后”的数字。

要了解DDL操作是in-place进行更改还是执行表复制的基本概念,请查看命令完成后显示的“受影响的行”值。例如,在执行不同类型的DDL操作后,您可能会看到以下行:
.更改列的默认值(超快,完全不影响表数据):

Query OK, 0 rows affected (0.07 sec)

.添加索引(需要时间,但是0行受影响表明表没有被复制):

Query OK, 0 rows affected (21.42 sec)

.更改列的数据类型(需要花费大量时间,并且需要重建表中的所有行):

Query OK, 1671168 rows affected (1 min 35.54 sec)

更改列的数据类型需要重建表中的所有行,VARCHAR大小的更改除外,这可以使用在线ALTER table执行。

例如,在一个大表上运行DDL操作之前,你可能会检查操作的快慢,如下所示:
1.克隆表结构。

2.用少量数据填充克隆表。

3.在克隆表上运行DDL操作。

4.检查“受影响的行”值是否为零。非零值意味着操作需要重建整个表,这可能需要特殊的规划。例如,您可以在计划的停机期间执行DDL操作,或者每次在每个复制从服务器上执行一个。

为了更深入地了解MySQL处理过程中的归约,可以查看DDL操作前后与InnoDB相关的performance_schema和INFORMATION_SCHEMA表,查看物理读、写、内存分配等的数量。

联机DDL操作的空间要求
联机DDL操作对空间的要求如下:
.存放临时日志文件的空间
对于每个创建的索引或修改的表,都有一个这样的日志文件。此日志文件存储在DDL操作期间在表中插入、更新或删除的数据。临时日志文件在需要时通过innodb_sort_buffer_size的值进行扩展,直到达到innodb_online_alter_log_max_size指定的最大值。如果临时日志文件的大小超过上限,那么ALTER TABLE操作将失败,所有未提交的并发DML操作将回滚。因此,如果该选项的值较大,就允许在联机DDL操作期间发生更多的DML,
但也会延长DDL操作结束时表被锁定以应用日志中的数据的时间。

如果操作花费的时间太长,并发的DML修改表的时间太长,导致临时在线日志的大小超过innodb_online_alter_log_max_size配置选项的值,则在线DDL操作失败,并出现DB_ONLINE_LOG_TOO_BIG错误。

.临时排序文件的空间
重建表的在线DDL操作在创建索引时将临时排序文件写入MySQL临时目录(Unix上为$TMPDIR, Windows上为%TEMP%,或由–tmpdir配置变量指定的目录)。每个临时排序文件都足够大,可以容纳新二级索引定义的所有列,以及聚集索引的主键的列,一旦合并到最终表或索引中,这些列就会被删除。此类操作需要的临时空间相当于存储表中数据和索引数据所需要的空间大小。如果重建表的联机DDL操作使用了数据目录(datadir)所在的文件系统上的所有可用磁盘空间,则会导致错误。

从MySQL 5.7.11开始,你可以使用innodb_tmpdir配置选项为联机DDL操作定义一个单独的临时目录。innodb_tmpdir选项的引入是为了避免在联机ALTER TABLE操作重建表时创建大型临时排序文件时可能发生的临时目录溢出。

.中间表文件的空间
一些重建表的联机DDL操作在与原始表相同的目录中创建临时中间表文件,而不是在原地重建表。中间表文件可能需要与原始表大小相等的空间。

联机DDL SQL语法
通常,当对InnoDB表使用ALTER TABLE语句时,不需要做任何特殊的事情来启用联机DDL。一些变体需要使用配置或与ALTER TABLE子句的特定组合。

通过使用ALTER TABLE语句的LOCK和ALGORITHM子句,可以控制特定联机DDL操作的各个方面。这些子句位于语句的末尾,用逗号与表和列的规范分隔。LOCK子句用于微调对表的并发访问程度。ALGORITHM子句主要用于性能比较并作为在现有DDL代码遇到任何问题时对旧表复制行为的回退。例如:
.为了避免意外地使表不可读、不可写或不可读和不可写,可以在ALTER table语句中指定一个子句,例如LOCK=NONE(允许读写)或LOCK=SHARED(允许读)。如果请求的并发级别不可用,操作将立即停止。

.为了比较性能,除了设置old_alter_table配置选项外,还可以运行一个ALGORITHM=INPLACE语句和另一个算法ALGORITHM=COPY的语句。

.为了避免复制表的ALTER TABLE操作占用服务器资源,可以使用ALGORITHM=INPLACE子名。如果不能使用in-place机制,该语句将立即停止。

使用联机DDL简化DDL语句
在引入联机DDL之前,将许多DDL操作组合到单个ALTER TABLE语句中是一种常见的做法。因为每个ALTER TABLE语句都涉及复制和重建表,所以一次对同一个表进行多次更改会更加高效,因为这些更改可以通过对表的一次重建操作完成。缺点是涉及DDL操作的SQL代码很难在不同的脚本中维护和重用。如果每次的具体更改都不同,则可能需要为每个稍有不同的场景构建一个新的复杂的ALTER TABLE。

对于可以in-place完成的DDL操作,现在,您可以将它们分离为单独的ALTER TABLE语句,以便于编写脚本和维护,而不会牺牲效率。例如,你可以用这样一个复杂的语句:

ALTER TABLE t1 ADD INDEX i1(c1), ADD UNIQUE INDEX i2(c2),
CHANGE c4_old_name c4_new_name INTEGER UNSIGNED;

将其分解为可以独立测试和执行的更简单的部分,例如:

ALTER TABLE t1 ADD INDEX i1(c1);
ALTER TABLE t1 ADD UNIQUE INDEX i2(c2);
ALTER TABLE t1 CHANGE c4_old_name c4_new_name INTEGER UNSIGNED NOT NULL;

你可能仍然要使用由多个部分组成的ALTER TABLE语句:
.必须按特定顺序执行的操作,例如创建索引,然后使用该索引的外键约束。

.所有操作都使用相同的特定LOCK子句,希望作为一个组成功或失败。

.不能in-place执行的操作,即仍然复制和重建表的操作。

.指定ALGORITHM=COPY或old_alter_table=1的操作,如果需要在特定场景中实现精确的向后兼容性,可以强制表复制行为。

联机DDL实现详细信息
InnoDB表的每个ALTER TABLE操作都受以下几个方面的控制:
.是否对表的物理表示有任何更改,或者是否纯粹是对元数据的更改,而无需触及表本身。

.表中的数据量是保持不变、增加还是减少

.表数据的更改是否涉及聚集索引、二级索引或两者。

.被修改的表与其他表之间是否存在外键关系。机制差异取决于foreign_key_checks配置选项是启用还是禁用。

.表是否被分区。ALTER TABLE的分区子句被转换为涉及一个或多个表的低级操作,这些操作遵循联机DDL的常规规则。

.是否必须复制表数据,表是否可以“in-place”重组,或者两者的组合。

.需要多大程度的锁定,取决于底层数据库操作的性质,或者取决于在ALTER TABLE语句中指定的LOCK子句。

联机DDL错误条件
以下是联机DDL操作可能失败的主要原因:
.如果LOCK子句指定了低级别锁(SHARED或NONE)将与特定类型的DDL操作不兼容。

.如果在等待获得表上的排他锁时发生超时,在DDL操作的初始和最后阶段可能需要短暂的超时。

.MySQL在创建索引时将临时排序文件写入磁盘,如果tmpdir或innodb_tmpdir文件系统耗尽了磁盘空间。

.如果ALTER TABLE花费了很长时间,并且并发的DML对表的修改太多,那么临时在线日志的大小超过了innodb_online_alter_log_max_size配置选项的值。这种情况会导致DB_ONLINE_LOG_TOO_BIG错误。

.如果并发DML对原表定义允许的表进行更改,但新表定义不允许。只有在最后,当MySQL试图应用并发DML语句中的所有更改时,操作才会失败。例如,用户可以在创建唯一索引时向列中插入重复的值,或者在创建主键索引时向列中插入NULL值。并发DML所做的更改优先,并且有效地回滚了ALTER TABLE操作。

尽管配置选项innodb_file_per_table对InnoDB表的表示有显著的影响,但是不管这个选项是启用还是禁用,不管表物理位置是在它自己的.ibd文件中还是在系统表空间中,所有的在线DDL操作都是一样的。

InnoDB有两种类型的索引:代表表中所有数据的聚集索引,以及可选的加速查询的二级索引。因为聚集索引包含其b树节点中的数据值,所以添加或删除聚集索引需要复制数据,并创建表的新副本。而二级索引只包含索引键和主键的值。可以在不复制聚集索引中的数据的情况下创建或删除这种类型的索引。因为每个二级索引都包含主键值的副本(用于在需要时访问聚集索引),所以当更改主键的定义时,也会重新创建所有二级索引。

删除二级索引很简单。只有内部的InnoDB系统表和MySQL数据字典表被更新,以反映索引不再存在的事实。InnoDB将用于索引的存储空间返回到包含它的表空间,以便新的索引或额外的表行可以使用该空间。

为了给已存在的表添加二级索引,InnoDB会扫描表,并使用内存缓冲区和临时文件,根据二级索引键列的值对行进行排序。B树是按键值顺序构建的,这比按随机顺序将行插入索引更高效。因为b树节点在填充时是分裂的,以这种方式构建索引会导致索引的填充因子更高,从而使后续访问更高效。

联机DDL和崩溃恢复
虽然在执行ALTER TABLE语句时服务器崩溃不会丢失数据,但是集群索引和二级索引的崩溃恢复过程是不同的。

如果服务器在创建InnoDB二索引时崩溃,在恢复时,MySQL删除所有部分创建的索引。您必须重新运行ALTER TABLE或CREATE INDEX语句。

当在创建InnoDB集群索引时发生崩溃时,恢复会更加复杂,因为表中的数据必须复制到一个全新的集群索引中。请记住,所有InnoDB表都存储为集群索引。

MySQL通过将原始InnoDB表中的现有数据复制到具有所需索引结构的临时表中来创建新的集群索引。一旦数据被完全复制到这个临时表中,原始表将被重命名为一个不同的临时表名。包含新聚集索引的临时表将使用原始表的名称重命名,原始表将从数据库中删除。

如果在创建新的聚集索引时发生系统崩溃,则不会丢失数据,但是必须使用该过程中存在的临时表来完成恢复过程。由于在此操作期间很少重新创建聚集索引或重新定义大型表上的主键,也很少遇到系统崩溃的情况,因此本手册不提供有关从此场景中恢复的信息。

分区表的联机DDL
大多数ALTER TABLE分区子句不会像常规的非分区InnoDB表那样使用相同的内部联机DDL API。因此,对ALTER TABLE分区子句的联机支持各不相同。

下表显示了每个ALTER TABLE分区语句的联机状态。不管使用的是哪种联机DDL API, MySQL都会尽可能地减少数据复制和锁定。
.”In-Place”列显示哪些操作允许使用ALGORITHM=INPLACE子句。

.”Permits Concurrent DML?”列显示哪些操作是完全联机执行的。您可以指定LOCK=NONE来断言在DDL操作期间允许并发DML。MySQL在可能的情况下自动允许并发DML。

对于支持ALGORITHM={COPY|INPLACE}的操作,可以指定LOCK=SHARED来断言DDL操作期间允许并发查询。MySQL在可能的情况下自动允许并发查询。

.“Notes”列提供了其他信息,并解释了与其他列的“Yes/No”值相关的异常和依赖关系。星号表示异常或依赖项。

使用ALGORITHM=COPY或只允许”ALGORITHM=DEFAULT, LOCK=DEFAULT”的ALTER TABLE分区选项,将使用COPY算法对表进行重新分区。换句话说,使用新的分区方案创建了一个新的分区表。新创建的表包含ALTER table语句应用的任何更改,表数据被复制到新的表结构中。

对分区表执行非分区联机ALTER TABLE操作遵循适用于常规表的相同规则。但是,ALTER TABLE在每个表分区上执行在线操作,由于在多个分区上执行操作,这会导致对系统资源的需求增加。

联机DDL限制
联机DDL操作存在以下限制:
.在TEMPORARY表上创建索引时复制表,而不是使用快速索引创建。这已经被报告为MySQL Bug #39833。

.当用户试图删除外键所需的索引时,InnoDB会处理错误。

.如果表上有ON…CASCADE或ON…SET NULLT约束,ALTER TABLE子句LOCK=NONE是不允许的。

.根据联机DDL操作的内部工作原理和ALTER TABLE语句的LOCK子句,联机DDL操作在DDL操作的初始阶段和最终阶段可能需要在短时间内对表进行排他访问。因此,如果有一个执行插入、更新、删除或对表执行SELECT … FOR UPDATE的长时间运行的事务并且如果在ALTER TABLE进行中启动了类似的长时间运行的事务,则联机DDL操作可能需要等待才能完成。

.当运行一个联机DDL操作时,运行ALTER TABLE语句的线程应用一个来自其他连接线程在同一个表上并发运行的DML操作的“在线日志”。当应用DML操作时,可能会遇到重复键条目错误(错误1062(23000):重复条目),即使重复条目只是临时的,并且会被“在线日志”中的稍后条目恢复。这类似于InnoDB中的外键约束检查,其中约束必须在事务期间保持。

.将InnoDB表的OPTIMIZE TABLE映射到ALTER TABLE以重建表并更新索引统计信息和释放聚集索引中的未使用空间。创建辅助索引的效率不高,因为键是按照它们在主键中出现的顺序插入的。通过添加在线DDL支持,可以重建常规的和分区的InnoDB表。

.在MySQL 5.6之前创建的InnoDB表,对于包括时间列(日期,日期时间或时间戳)的表不支持ALTER TABLE…ALGORITHM=INPLACE且不能使用ALTER TABLE…ALGORITHM=COPY进行重建。在这种情况下,ALTER TABLE…ALGORITHM=INPLACE操作返回如下错误:

ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported.
Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.

.这些限制通常适用于涉及表复制的大型表上的在线DDL操作:
.不存在暂停在线DDL操作或限制在线DDL操作的I/O或CPU使用的机制DDL操作。

.如果操作失败,回滚在线DDL操作的代价可能很高。

.长时间运行在线DDL操作可能导致复制滞后。在线DDL操作必须在主节点上运行完之后才能在从节点上运行。此外,在主服务器上并发处理的DML只有在从服务器上的DDL操作完成后才会在从服务器上处理(Bug #73196)。

发表评论

电子邮件地址不会被公开。