创建索引
https://dev.mysql.com/doc/refman/5.6/en/innodb-online-ddl-operations.html
ALTER TABLE tbl_name ADD PRIMARY KEY (column), ALGORITHM=INPLACE, LOCK=NONE;
ALTER TABLE tbl_name ADD COLUMN column_name column_definition, ALGORITHM=INPLACE, LOCK=NONE;
ALTER TABLE `member` ADD `user_from` smallint(1) NOT NULL, ALGORITHM=INPLACE, LOCK=NONE
Performance and Space Requirements
ALTER TABLE操作有两种算法(ALGORITHM):
COPY: 操作在原表的副本表上进行,表数据逐行拷贝自原表。不支持并发DML。
INPLACE: 操作避免复制表数据,但可能会就地rebuild表。在准备和执行阶段,可能会短暂地独占元数据锁。通常,支持并发DML
ALGORITHM
子句是可选项。如果没有指定ALGORITHM
,或者指定ALGORITHM=DEFAULT
,MySQL则在支持的引擎和alter操作使用 ALGORITHM=INPLACE
;否则使用 ALGORITHM=COPY
。
注意
分区表不支持ALGORITHM=DEFAULT
,ALGORITHM=INPLACE
, andALGORITHM=COPY
。
MySQL 5.6.11及以后的版本,分区表使用ALGORITHM=1
andALGORITHM=2
来升级/降级。
参见Section 13.1.7.1, “ALTER TABLE Partition Operations”。
指定ALGORITHM子句需要使用的操作和存储引擎支持,否则会报错。指派ALGORITHM=DEFAULT
等同于忽略配置。
使用COPY
算法的ALTER TABLE
操作,依赖其他表修改操作来完成。在副本表更改后,将复制数据,删除原始表,并将副本表重命名为原始表的名称。在执行 ALTER TABLE
操作时,其他会话可以读取原始表 (with the exception noted shortly)。在ALTER table
操作开始后,对表的更新和写入被暂停,直到新表准备就绪,然后自动重定向到新表。临时表在原始表的同目录中创建,除非RENAME TO
到其他目录。
前面提到的 exception ,ALTER TABLE
在准备安装新版本的表.frm
文件时,会阻止读取(不仅是写),丢弃旧文件,从表&表定义缓存中清除过期表结构。这时,它必须独占锁。为此,要等待当前读结束,并阻止新的读写。
使用COPY
算法的ALTER TABLE
操作可防止并发DML,允许并发查询。也就是说,table-copying操作至少限制在LOCK=SHARED
(允许查询,但不允许DML)。LOCK=EXCLUSIVE
则阻止DML和查询,进一步限制了支持LOCK子句的操作的并发性。
参见Concurrency Control
Note
MySQL 5.6,LOCK在分区表上不支持 ALTER TABLE 操作
要强制将COPY
算法用于本来不使用其的ALTER TABLE
操作,需要开启 old_alter_table
系统变量,或指定ALGORITHM=COPY
。如果old_alter_table
和非默认值的ALGORITHM
冲突,则ALGORITHM
子句优先。
对于InnoDB表,对驻留在共享表空间(如 system tablespace)中的表,使用COPY
算法的ALTER TABLE
操作会增加表空间的使用量。这些操作需要同增加索引一样多的额外空间。对于驻留在共享表空间中的表,操作使用的额外空间不会释放回操作系统,as it is for a table that resides in a file-per-table tablespace。
关于空间需求参见Section 14.13.3, “Online DDL Space Requirements”
使用INPLACE
算法的ALTER TABLE
操作:
InnoDB
online DDL特性支持的ALTER TABLE
操作。参见 Section 14.13.1, “Online DDL Operations”.重命名表。MySQL重命名与表
tbl_name
相关的文件,无需拷贝。也可以使用RENAME TABLE
来重命名表。参见 Section 13.1.32, “RENAME TABLE Statement”.) 。权限需要手动修改,原表权限不会迁移到重命名后的表。-
只修改表元数据的操作。这些是实时操作,因为服务器仅更改表
.frm
文件,不创建表内容。元数据操作包含:- 重命名列
- 改变列的默认值 ,
NDB
表不适用。参见Limitations of NDB online operations。 - 修改枚举
ENUM
or集合SET
列的定义,通过在有效成员值列表的末尾添加新的枚举或集合成员,只要数据类型的存储大小不变。比如,添加一个成员到拥有8个成员的某SET
列,会将每个值所需的存储空间从1字节更改为2字节,那么需要table copy。 在列表中间添加成员会导致现有成员重新编号,也需要table copy。
在
InnoDB
和NDB
表,创建、删除二级索引。参见Section 14.13, “InnoDB and Online DDL”。对于
NDB
表,在variable-width列上增加、删除索引的操作。这些操作在线进行,无需table copying ,并且在大部分时间内不会阻止并发DML操作。参见 Section 18.6.11, “Online Operations with ALTER TABLE in NDB Cluster”。
从MySQL 5.6.16开始,对于ADD COLUMN
, CHANGE COLUMN
, MODIFY COLUMN
, ADD INDEX
, and FORCE
操作,ALTER TABLE
会将MySQL 5.5临时列升级为5.6格式。无法使用 INPLACE
算法完成此转换,因为必须rebuild表,因此该情况下指定ALGORITHM=INPLACE
会报错。如果需要,指定 ALGORITHM=COPY
。
NDB Cluster支持在MySQL NDB Cluster 7.3及更高版本中,使用 ALGORITHM=INPLACE
语法进行在线ALTER TABLE操作。NDB集群还支持NDB特有的旧语法的ONLINE
and OFFLINE
关键字。这些关键字从MySQL NDB Cluster 7.3开始就被弃用;MySQL NDB Cluster 7.4中仍然支持它们,但在NDB Cluster的未来版本中可能会删除它们。参见 Section 18.6.11, “Online Operations with ALTER TABLE in NDB Cluster”。
根据KEY来对表分区的多列索引,如果ALTER TABLE
操作作用于该多列索引上变更了列的顺序,则只能使用ALGORITHM=COPY
。
MySQL NDB Cluster 7.3(及更高版本)支持使用ALGORITHM=INPLACE
语法(与标准MySQL服务器相同)的在线操作。NDB Cluster 7.3和7.4还继续支持使用ONLINE
and OFFLINE
关键字进行在线ALTER TABLE操作,以实现向后兼容性,但NDB 7.3和7.4中不推荐使用这些关键字,并且从NDB 7.5起不再支持这些关键字。NDB
不支持在线变更表空间。参见Section 18.6.11, “Online Operations with ALTER TABLE in NDB Cluster”。
ADD PARTITION
, DROP PARTITION
, COALESCE PARTITION
, REBUILD PARTITION
, or REORGANIZE PARTITION
这些ALTER TABLE
操作不会创建临时表 (NDB
表除外);然而, 这些操作确实可以创建临时分区文件。
对于RANGE
or LIST
分区,ADD
or DROP
是实时或几乎实时的操作。
对于HASH
or KEY
分区,ADD
or COALESCE
操作从所有分区拷贝数据,除非使用了LINEAR HASH
or LINEAR KEY
;这实际上与创建新表相同,尽管ADD
or COALESCE
操作是逐个分区执行的。
REORGANIZE
操作只复制已更改的分区,不接触未更改的分区。
对于MyISAM表,通过将myisam_sort_buffer_size
系统变量调高,可以加快索引的重建速度,这是alter过程中最慢的部分。
并发控制 Concurrency Control
对于支持Concurrency Control的ALTER TABLE
操作,可以使用LOCK
子句在表被alter时控制表上并发读写的级别。
非默认值的指定,使得在alter操作期间,您可以请求一定量的并发/独占访问,并可以在请求的锁定程度不再可用时停止操作。
- LOCK = DEFAULT
如果支持,允许并发读取。
如果不支持并发读取,支持并发读,则允许并发读。
如果也不支持并发读,则强制排它访问。 - LOCK = NONE
允许并发读写。如果不支持并发读写,则报错。 - LOCK = SHARED
允许并发读取,不允许块写入。即便给定的ALGORITHM子句和 ALTER TABLE操作支持并发写,也不可以。如果不支持并发读,则报错。 - LOCK = EXCLUSIVE
强制排它访问。即便给定的ALGORITHM子句和 ALTER TABLE操作支持并发读/写,也要执行此操作。
online DDL的空间要求:
由于online DDL执行期间需要创建临时表空间文件用于存储数据,以及申请row log记录DML操作,所以在执行DDL前应该先确认空间上是否满足要求,否则由于空间不够很可能导致操作失败,而进行回滚。
1、row log空间:row log空间每次申请的大小由 innodb_sort_buffer_size决定,最大值由innodb_online_alter_log_max_size,该值默认为128M,支持动态修改。对于更新频繁的表来讲,如果预计在DDL期间对表的更新操作存储可能超过128M时,需要为本次操作增大该值。当然如果不涉及rebuild操作时,不需要考虑该值。如果提示DB_ONLINE_LOG_TOO_BIG错误,则是由innodb_online_alter_log_max_size空间不足造成的。
2、索引排序空间:如果DDL操作涉及二级索引的创建,会在MySQL临时目录产生临时排序文件,将中间的排序结果写入文件,最终将内容合并到最终表或索引中,然后自动删除临时排序文件。这个路径默认为mysql全局参数tmpdir指定(默认值为/tmp,如果手动指定了innodb_tmpdir参数的路径,则tmpdir会被覆盖),且不会在原始表的目录中创建临时排序文件。tmpdir需要保证能够容纳要创建的二级索引,临时排序文件最大可能需要的空间等于表中的数据量加上索引,否则执行将报错。(官方文档的说明,实际测试200万的表加索引,并未生成临时排序文件,这有点奇怪)
3、中间表空间:如果DDL操作涉及rebuild表,则会在原表所在目录创建临时表空间文件(以#sql开头),临时表空间大小需要等于原表大小,重建完成后会自动重命名临时表空间,删除原表空间。所以执行rebuild操作时需要保证原表所在路径下有足够空间
参考资料 :
https://c4ys.com/archives/1943
MySQL 5.6 Reference Manual / The InnoDB Storage Engine
InnoDB and Online DDL
Online DDL Operations
CREATE INDEX Statement
ALTER TABLE Statement