MySQL Online DDL学习笔记
MySQL online DDL的功能就是在对表就行DDL操作的同时也可以对表进行读写操作,
即对表的DDL操作不会影响该表上的事务。
该功能的优点:
- 改善繁忙生产环境的响应效率和可用性。
- 可以使用lock子句在性能和并发性之间进行协调。
- 相比ALGORITHM=COPY算法使用较少的磁盘空间和IO的开销。
使用了ALGORITHM,LOCK子句的onlin DDL:
ALTER TABLE tbl_name ADD PRIMARY KEY (column), ALGORITHM=INPLACE, LOCK=NONE;
lock子句用于设置DDL执行期间,该表上的并发程度
ALGORITHM=INPLACE
and ALGORITHM=COPY子句用于设置online DDL的处理算法,进行DDL时一定要尽量避免出现table copy
DDL online支持总览表:
Operation | In Place | Rebuilds Table | Permits Concurrent DML | Only Modifies Metadata | Notes |
---|---|---|---|---|---|
CREATE INDEX , ADD INDEX |
Yes* | No* | Yes | No | Restrictions apply for FULLTEXT indexes; see next row. |
ADD FULLTEXT INDEX |
Yes* | No* | No | No | Adding the first FULLTEXT index rebuilds the table if there is no user-defined FTS_DOC_ID column. Subsequent FULLTEXT indexes may be added on the same table without rebuilding the table. |
ADD SPATIAL INDEX |
Yes | No | No | No | |
RENAME INDEX |
Yes | No | Yes | Yes | Only modifies table metadata. |
DROP INDEX |
Yes | No | Yes | Yes | Only modifies table metadata. |
OPTIMIZE TABLE |
Yes* | Yes | Yes | No | In-place operation is not supported for tables with FULLTEXT indexes. |
Set column default value | Yes | No | Yes | Yes | Only modifies table metadata. |
Change auto-increment value | Yes | No | Yes | No* | Modifies a value stored in memory, not the data file. |
Add foreign key constraint | Yes* | No | Yes | Yes | The INPLACE algorithm is supported when foreign_key_checks is disabled. Otherwise, only the COPY algorithm is supported. |
Drop foreign key constraint | Yes | No | Yes | Yes | foreign_key_checks can be enabled or disabled. |
Rename column | Yes* | No | Yes* | Yes | To permit concurrent DML, keep the same data type and only change the column name. ALGORITHM=INPLACE is not supported for renaming agenerated column. |
Add column | Yes* | Yes* | Yes* | No | Concurrent DML is not permitted when adding an auto-increment column. Data is reorganized substantially, making it an expensive operation. ALGORITHM=INPLACE is supported for adding a virtual generated column but not for adding a stored generated column. Adding a virtual generated column does not require a table rebuild. |
Drop column | Yes | Yes* | Yes | No | Data is reorganized substantially, making it an expensive operation.ALGORITHM=INPLACE is supported for dropping a generated column. Dropping a virtual generated column does not require a table rebuild. |
Reorder columns | Yes | Yes | Yes | No | Data is reorganized substantially, making it an expensive operation. |
Change ROW_FORMAT property |
Yes | Yes | Yes | No | Data is reorganized substantially, making it an expensive operation. |
Change KEY_BLOCK_SIZE property |
Yes | Yes | Yes | No | Data is reorganized substantially, making it an expensive operation. |
Make column NULL |
Yes | Yes* | Yes | No | Rebuilds the table in place. Data is reorganized substantially, making it an expensive operation. |
Make column NOT NULL |
Yes* | Yes | Yes | No | Rebuilds the table in place. STRICT_ALL_TABLES orSTRICT_TRANS_TABLES SQL_MODE is required for the operation to succeed. The operation fails if the column contains NULL values. The server prohibits changes to foreign key columns that have the potential to cause loss of referential integrity. See Section 13.1.8, “ALTER TABLE Syntax”. Data is reorganized substantially, making it an expensive operation. |
Change column data type | No* | Yes | No | No | VARCHAR size may be increased using online ALTER TABLE . See Modifying Column Properties for more information. |
Add primary key | Yes* | Yes* | Yes | No | Rebuilds the table in place. Data is reorganized substantially, making it an expensive operation.ALGORITHM=INPLACE is not permitted under certain conditions if columns have to be converted to NOT NULL . |
Drop primary key and add another | Yes | Yes | Yes | No | Data is reorganized substantially, making it an expensive operation. |
Drop primary key | No | Yes | No | No | Only ALGORITHM=COPY supports dropping a primary key without adding a new one in the same ALTER TABLE statement. |
Convert character set | No | Yes* | No | No | Rebuilds the table if the new character encoding is different. |
Specify character set | No | Yes* | No | No | Rebuilds the table if the new character encoding is different. |
Rebuild with FORCE option |
Yes* | Yes | Yes | No | Uses ALGORITHM=INPLACE .ALGORITHM=INPLACE is not supported for tables with FULLTEXT indexes. |
“null” rebuild using ALTER TABLE ... ENGINE=INNODB |
Yes* | Yes | Yes | No | Uses ALGORITHM=INPLACE .ALGORITHM=INPLACE is not supported for tables with FULLTEXT indexes. |
Set STATS_PERSISTENT ,STATS_AUTO_RECALC ,STATS_SAMPLE_PAGES persistent statistics options |
Yes | No | Yes | Yes | Only modifies table metadata. |
ALTER TABLE … ENCRYPTION |
No | Yes | No | Yes | |
Drop a STORED column |
Yes | Yes* | Yes | No | Rebuilds the table in place. |
Modify STORED column order |
Yes | Yes* | Yes | No | Rebuilds the table in place. |
Add a STORED column |
Yes | Yes* | Yes | No | Rebuilds the table in place. |
Drop a VIRTUAL column |
Yes | No | Yes | Yes | |
Modify VIRTUAL column order |
Yes | No | Yes | Yes | |
Add a VIRTUAL column |
Yes | No | Yes | Yes |
常用的online DDL:
创建二级索引:
CREATE INDEX name ON table (col_list);
ALTER TABLE table ADD INDEX name (col_list);
删除二级索引:
DROP INDEX name ON table; ALTER TABLE tbl_name DROP INDEX name;
在innodb表上创建和删除二级索引不会产生table-copying
当索引正在被创建或删除时,是可以对表进行读写操作的, 在对表执行create index或drop index语句时,只有在访问该表的事务完成之后,create index和drop index语句才可以完成,所以索引的初始状态反映了表中最新的数据,在以前,对正在执行create index或drop index的表进行操作时,会导致将insert,update,delete操作撤销掉的死锁。
online ddl的另外一个用法是,在进行数据迁移时,可以先创建表结构,然后导入数据,最后创建相关索引,这种方式通常会提高数据迁移的效率。
新创建的二级索引只包含在create index和alter table语句完成时,已经在该表上commit的数据,不包含未提交的值,old version值,已经标记删除的值。
如果在创建二级索引时,MySQL崩溃或是异常宕机,在恢复时,MySQL会drop掉创建了一半的索引,所以此时需要重新手动创建索引。
重命名索引也是online DDL
ALTER TABLE tbl_name RENAME INDEX old_index_name TO new_index_name, ALGORITHM=INPLACE, LOCK=NONE;
创建全文索引:
CREATE FULLTEXT INDEX name ON table(column);
如果在创建第一个全文索引时,如果FTS_DOC_ID列之前没有创建过,那么创建全文索引需要rebuild table,在之后创建全文索引时是online状态的,不需要rebuild table。
添加和删除主键索引:
重建聚集索引总是要进行copy table,所以在建表时一定要设计好主键,尽量在之后使用alter table来修改
只有当sql_mode的设置包含了 strict_trans_tables
或strict_all_tables
标记时, ALGORITHM=INPLACE是允许的
但是创建主键的列包含null值的话,会导致语句执行失败。
如果表中没有主键,innodb会自动选择第一个被定义为not null unique的字段作为主键,或是在内部自动生成一个自动作为主键,但这会有隐藏的空间开销。
MySQL创建新的聚集索引是通过将原表中已存在的数据copy到按照目标索引结构产生的临时表中,在数据copy完成后,将该临时表rename为原来的表的名称,
并将原表从数据库中drop掉。
因为MySQL是索引组织表,表的结构与主键密切相关,所以重定义主键一定会导致copy table,
此时使用ALGORITHM=INPLACE虽然会出现copy table,但仍比ALGORITHM=COPY的效率要高,因为:
- 不产生undo和redo日志。
- 二级索引的记录是预先排好序的,所以可以按照顺序导入。
- 没有使用到change buffer,因为没有随机访问insert到二级索引。
ALTER TABLE tbl_name DROP PRIMARY KEY, ALGORITHM=COPY;
只有ALGORITHM=COPY模式支持drop primary key.
ALTER TABLE tbl_name DROP PRIMARY KEY, ADD PRIMARY KEY (column), ALGORITHM=INPLACE, LOCK=NONE;
数据会大量重组,该操作是一个开销很大操作。
修改字段的属性值:
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;
在使用复制的分布式系统,或者是分片中,需要重新设置自增值到某一个指定的值,在数据仓库中,有时需要清空表中的数据,然后重置自增值,再导入新的数据。
重命名字段名称:
ALTER TABLE tbl CHANGE old_col_name new_col_name datatype;
当使用该语句只是修改字段的名称,而没有修改字段类型时,该语句的执行总是online的。
在对外键约束中的字段进行重命名后,在外键的定义中会自动将该字段的名称更新为重命名后的名称,对外键中的字段进行重命名操作时,该操作仅运行在 in-place模式,
当在修改语句中指定 ALGORITHM=COPY或者其他因素导致修改语句使用了
ALGORITHM=COPY,那么重命名字段的语句将会执行失败。
使用in-place模式修改varchar字段的长度:
ALTER TABLE t1 ALGORITHM=INPLACE, CHANGE COLUMN c1 c1 VARCHAR(255);
每次修改varchar字段的长度时,varchar内部编码需要的字节长度值一定要保持相同,因为varchar值从0-255时,需要1个字节长度来编码值,当varchar从256字节开始需要2个字节长度来编码值,所以当修改varchar字段的长度时,从0字节增加到255字节,或者从大于等于256字节开始增加长度都是支持in-place模式的,当从一个小于256字节的长度增加到大于256字节的长度,因为此时会导致varchar内部编码值所需要的字节长度从1个字节长度变为2个字节长度,所以此时不能使用in-place模式,只能使用ALGORITHM=COPY模式,例如下述修改varchar长度的语句将会执行失败:
ALTER TABLE t1 ALGORITHM=INPLACE, CHANGE COLUMN c1 c1 VARCHAR(256);
ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.
缩小varchar字段的长度时不支持in-place模式的,此时需要进行table copy(ALGORITHM=COPY
).
添加删除外键:
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参数为disable时,创建外键是online的。删除外键时,与该参数的取值无关,都是online状态的。
删除外键和索引:
ALTER TABLE table DROP FOREIGN KEY constraint, DROP INDEX index;
当外键已经作用于正在被修改的表时,进行online DDL会存在一些额外的限制:
如果在子表上进行alter table操作,当存在ON UPDATE或者使用了CASCADE和SET NULL参数的
ON DELETE子句时,导致子表的数据随着父表进行变化,
那么子表上的alter table语句要等待父表上的事务commit,同理,在父表上进行alter table操作,也要等待子表上的相关事务commit。
因为在进行DDL操作时,对表的读写操作不会受到影响,所以提高了应用的响应效率。
由于in-place操作不需要rebuild table,所以节省了磁盘IO和cpu的开销,最小化了数据库的负载,在执行DDL期间提供了较好的性能。
相对于copy table,in-place操作只是将较少的数据读入到buffer pool中,避免了将频繁使用的数据从buffer pool中冲走,在以前版本,进行DDL操作会导致系统性能降低。
Online DDL的locking选项
通过lock子句强制使用更严格的锁模式,如果lock子句指定锁的严格程度低于某些DDL的最低锁严格程度,那么多将会报错,
LOCK=NONE
:
允许并发查询和DML
LOCK=SHARED
:
允许并发查询,但是阻塞DML
LOCK=DEFAULT
:
尽量满足最大并发,如果没有指定lock子句,默认为此模式
LOCK=EXCLUSIVE
:
阻塞并发查询和DML
当主要关心的是在尽可能短的时间内完成DDL,而并发查询和DML的执行不重要的情况下,使用此模式
在大多数情况,在表上的online DDL操作会等待当前正在访问该表的事务commit或rollback,因为当DLL语句正在准备的时候,需要对表进行短暂的排他访问。
同理online DDL在完成之前需要对表进行一个短暂的排他访问。所以,如果运行在该表上的事务执行时间过长,那么会导致online DDL等待排他访问超时。
未完待续
本博客刚刚开通,旨在将本人的工作和学习经验在此分享,因为之前的资料杂乱无章,过于零碎,所以整理的时间会长一些,很多地方也没有描述清楚,在后续过程中会进一步整理。