基本概念
在开始阅读前,先熟悉下以下概念,以便更加方便理解。
DML
DML(Data Manipulation Language)数据操作语言-数据库的基本操作,SQL中处理数据等操作统称为数据操纵语言,简而言之就是实现了基本的“增删改查”操作。包括的关键字有:select、update、delete、insert、merge
DDL
DDL(Data Definition Language)数据定义语言-用于定义和管理 SQL 数据库中的所有对象的语言,对数据库中的某些对象(例如,database,table)进行管理。包括的关键字有:create、alter、drop、truncate、comment、grant、revoke
SQL_MODE
为当前会话设置严格模式:
执行SET sql_mode = ‘STRICT_TRANS_TABLES’ 或者SET sql_mode = ‘STRICT_ALL_TABLES’
全局设置严格模式:
执行SET global sql_mode = ‘STRICT_TRANS_TABLES’ 或者SET global sql_mode = ‘STRICT_ALL_TABLES’
INPLACE/COPY算法
在执行DDL时复制表数据,INPLACE表示不会复制表数据,COPY表示会复制表数据
重建表(Rebuild Table)
在执行DDL的时是否需要重建表,例如对于InnoDB,因为其是基于主键(聚集索引)组织数据的,所以如果修改主键(如增加一列),则会需要重建表。
允许并发DML
在执行DDL时是否允许并发的DML。例如,在增加一个二级索引时,允许对数据库执行DML等操作。
只修改元数据
在执行DDL时是否只修改表的元数据,而不需要修改数据。例如,对于修改表名,只需要修改该表的元数据,而不需要触及该表的数据。
索引操作
下表概述了对索引操作的在线 DDL 支持。星号表示附加信息、异常或依赖关系。
索引操作的在线 DDL 支持:
操作 | IN PLACE 算法 | 重建表(Rebuild Table) | 允许并发DML | 只修改元数据 | 说明 |
---|---|---|---|---|---|
创建或添加二级索引 | Yes | No | Yes | No | 创建的二级索引包含在创建index结束之前提交的数据,不包含未提交的数据,旧版本的数据,被标记为删除但未从旧索引删除的数据。 |
删除索引 | Yes | No | Yes | Yes | 只有在所有访问该表的事务都结束后才会结束删除索引,即索引的初始状态是表的最近状态。 |
重命名索引 | Yes | No | Yes | Yes | 只修改元数据而不触及数据 |
添加FULLTEXT索引 | Yes* | No* | No | No | 如果没有用户定义的FTS_DOC_ID列,则需要重建表;其他的不需要重建表。 |
添加SPATIAL索引 | Yes | No | No | No | 与FULLTEXT相同。 |
更改索引类型 | Yes | No | Yes | Yes | 修改索引类型,USING BTREE 或者HASH,与重建索引类似 |
如果服务器在创建二级索引时退出,则在恢复时,MySQL 会删除任何部分创建的索引。您必须重新运行ALTER TABLE orCREATE INDEX语句。
主键操作
索引操作的在线 DDL 支持:
操作 | IN PLACE 算法 | 重建表(Rebuild Table) | 允许并发DML | 只修改元数据 | 说明 |
---|---|---|---|---|---|
添加主键索引 | Yes* | Yes* | Yes | No | 新增主键,需要重建数据表(根据聚集索引重排)。 如果有列必须要从NULL转成NOT NULL,那么不允许INPLACE算法。 |
删除主键索引 | No | Yes | No | No | 在删除主键而不增加新主键时,只有COPY方式才能被使用 |
删除并且增加另一个主键索引 | Yes | Yes | Yes | No | 需要重建表,所以此操作的代价非常大。 |
新增主键: 当新建UNIQUE和PK时,MySQL需要做重复值检查,对于PK,还需要检查不包含NULL值。使用COPY方式时,MySQL会将NULL转为对应的默认值(数字为 0,基于字符的列和 BLOB 为空字符串,0000-00-00 00:00:00 为DATETIME)。为了支持INPLACE,需要设置SQL_MODE(strict_trans_tables或strict_all_tables)。
新建主键的过程如下:从数据从原表t中复制到新的临时表t1(新的主键/聚集索引)中,然后将原表重命名到一个临时表的名字t2,然后将新索引的临时表t1重命名为原表名t,最后将旧表t2删除。
当采用INPLACE时,即使数据仍然需要复制,但性能仍然会比COPY方式要好:
- INPLACE不需要UNDO/REDO log;
- 二级索引是预排序的,能够有序地读取;
- 不需要更改缓冲区,因为没有二级索引的随机插入;
列操作
下表概述了对列操作的在线 DDL 支持。星号表示附加信息、异常或依赖关系。
操作 | IN PLACE 算法 | 重建表(Rebuild Table) | 允许并发DML | 只修改元数据 | 说明 |
---|---|---|---|---|---|
添加列 | Yes | Yes | Yes* | No | 添加列时不允许并发 DML 。需要重建表,所以此操作的代价非常大。所以增加列时可以增加 ALGORITHM=INPLACE, LOCK=SHARED。 |
删除列 | Yes | Yes | Yes | No | 需要重建表,所以此操作的代价非常大。 |
重命名列 | Yes | No | Yes* | Yes | 如果需要允许并发 DML,需要保持相同的数据类型和[NOT] NULL属性,只改变列名。如果重命名属于外键约束的列,外键定义会自动更新以使用新的列名。重命名参与外键的列仅适用于 ALGORITHM=INPLACE. 如果您使用该 ALGORITHM=COPY子句,或者某些其他条件导致操作使用 ALGORITHM=COPY,则该ALTER TABLE语句将失败。 |
重新排序列 | Yes | Yes | Yes | No | 需要重建表,所以此操作的代价非常大。 |
设置列默认值 | Yes | No | Yes | Yes | 仅修改表元数据。默认列值存储在表的.frm 文件 中,而不是InnoDB 数据字典中。 |
更改列数据类型 | No | Yes | No | No | 仅支持更改列数据类型 ALGORITHM=COPY。 |
扩展VARCHAR列大小 | Yes | No | Yes | Yes | |
删除列默认值 | Yes | No | Yes | Yes | 仅修改表元数据。默认列值存储在表的.frm 文件 中,而不是InnoDB 数据字典中。 |
更改自动增量值 | Yes | No | Yes | No* | 修改存储在内存中的值,而不是数据文件。 |
修改列为NULL | Yes | Yes* | Yes | No | 需要重建表,所以此操作的代价非常大。 |
修改列为NOT NULL | Yes* | Yes* | Yes | No | 需要重建表,所以此操作的代价非常大。 |
修改定义为enum或者set列 | Yes | No | Yes | Yes |
重新排序列
如果需要重新排序列,使用FIRST或者 AFTER in CHANGE或者 MODIFY操作。
ALTER TABLE tbl_name MODIFY COLUMN col_name column_definition FIRST, ALGORITHM=INPLACE, LOCK=NONE;
扩展VARCHAR列大小
扩展VARCHAR列大小操作是平常最常见的操作了。列的字节长度VARCHAR取决于字符集的字节长度,ascii为一个字节(单字节),utf8为三个字节。
对于VARCHAR大小为 0 到 255 字节的列,需要一个长度字节来对值进行编码。
对于VARCHAR 大小为 256 字节或更多的列,需要两个长度字节。
ALTER TABLE仅支持将 VARCHAR列大小从 0 字节增加到 255 字节,或从 256 字节增加到更大的大小。
ALTER TABLE不支持增加a列的大小 VARCHAR从小于 256 字节到等于或大于 256 字节的列。在这种情况下,所需的长度字节数从 1 变为 2,这情况只能使用ALGORITHM=COPY。例如,尝试VARCHAR使用将单字节字符集(例如ascii)的列大小从 VARCHAR(255) 更改为 VARCHAR(256) ,ALTER TABLE返回错误。如果使用utf8字符集则可以成功修改。
ascii字符集表使用ALGORITHM=INPLACE将varchar(200)修改为varchar(256):
ALTER TABLE employee ALGORITHM=INPLACE, CHANGE COLUMN remark remark VARCHAR(300);
ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.
ascii字符集表使用ALGORITHM=COPY将varchar(200)修改为varchar(256):
ALTER TABLE employee ALGORITHM=copy , CHANGE COLUMN remark remark VARCHAR(300)
[2023-01-07 17:09:38] 1 row affected in 88 ms
不支持VARCHAR减小尺寸。ALTER TABLE减小VARCHAR 大小需要使用ALGORITHM=COPY。ascii或者utf8字符集表都不支持使用ALGORITHM=INPLACE。
VARCHAR(300)修改为VARCHAR(288):
ALTER TABLE employee ALGORITHM=INPLACE , CHANGE COLUMN remark remark VARCHAR(288);
ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.
ALTER TABLE employee ALGORITHM=copy , CHANGE COLUMN remark remark VARCHAR(288)
[2023-01-07 17:12:36] 1 row affected in 97 ms
STORED操作
STORED列可能比较陌生。
举个例子:
user表有姓(surname)和name(名),创建一个full_name(全名) STORED列
ALTER TABLE user ADD COLUMN (full_name varchar(12) GENERATED ALWAYS AS (concat(surname,name)) STORED), ALGORITHM=COPY;
插入数据查询如下:
insert into user(surname, name) VALUES ('孙','悟空'),('诸葛','亮');
select * from user;
下表概述了对STORED列操作的在线 DDL 支持。
操作 | IN PLACE 算法 | 重建表(Rebuild Table) | 允许并发DML | 只修改元数据 | 说明 |
---|---|---|---|---|---|
添加STORED列 | No | Yes | No | No | 需要重建表,所以此操作的代价非常大。 |
修改STORED列顺序 | No | Yes | No | No | 需要重建表,所以此操作的代价非常大。 |
删除STORED列 | Yes | Yes | Yes | No | 需要重建表,所以此操作的代价非常大。 |
添加VIRTUAL列 | Yes | No | Yes | Yes | |
修改VIRTUAL列顺序 | No | Yes | No | No | 需要重建表,所以此操作的代价非常大。 |
删除VIRTUAL列 | Yes | No | Yes | Yes |
外键操作
下表概述了对外键操作的在线 DDL 支持。星号表示附加信息、异常或依赖关系。
操作 | IN PLACE 算法 | 重建表(Rebuild Table) | 允许并发DML | 只修改元数据 | 说明 |
---|---|---|---|---|---|
添加外键约束 | Yes* | No | Yes | No | 当FOREIGN_KEY_CHECKS被禁用时,可以用INPLACE;否则只能COPY。 |
删除外键约束 | Yes | No | Yes | Yes | 当FOREIGN_KEY_CHECKS被禁用时,可以用INPLACE;否则只能COPY。 |
FOREIGN_KEY_CHECKS
FOREIGN_KEY_CHECKS是用来启动和关闭外键约束的方法。
SELECT @@FOREIGN_KEY_CHECKS;查看当前FOREIGN_KEY_CHECKS的值
SET FOREIGN_KEY_CHECKS = 0;关闭外键约束
SET FOREIGN_KEY_CHECKS = 1;启动外键约束
表操作
下表概述了表操作的在线 DDL 支持。星号表示附加信息、异常或依赖关系。
操作 | IN PLACE 算法 | 重建表(Rebuild Table) | 允许并发DML | 只修改元数据 | 说明 |
---|---|---|---|---|---|
改变ROW_FORMAT | Yes | Yes | Yes | No | 需要重建表,所以此操作的代价非常大。 |
改变KEY_BLOCK_SIZE | Yes | Yes | Yes | No | 需要重建表,所以此操作的代价非常大。 |
设置持久表统计信息 | Yes | No | Yes | Yes | 仅修改表元数据。 |
指定字符集 | Yes | Yes* | No | No | |
转换字符集 | No | Yes* | No | No | 需要重建表,所以此操作的代价非常大。 |
优化表 | Yes* | Yes | Yes | No | |
FORCE使用选项重建 | Yes* | Yes | Yes | No | |
执行空重建 | Yes* | Yes | Yes | No | |
重命名表 | Yes | No | Yes | Yes |
改变ROW_FORMAT
ALTER TABLE tbl_name ROW_FORMAT = row_format, ALGORITHM=INPLACE, LOCK=NONE;
需要重建表,所以此操作的代价非常大。
改变KEY_BLOCK_SIZE
ALTER TABLE tbl_name KEY_BLOCK_SIZE = value, ALGORITHM=INPLACE, LOCK=NONE;
需要重建表,所以此操作的代价非常大。
KEY_BLOCK_SIZE
创建innodb表时带上ROW_FORMAT=COMPRESSED参数能够使用比默认的16K更小的页。这样在读写时需要更少的I/O,对于SSD磁盘更有价值。
页的大小通过KEY_BLOCK_SIZE参数指定。
设置持久表统计选项
ALTER TABLE tbl_name STATS_PERSISTENT=0, STATS_SAMPLE_PAGES=20, STATS_AUTO_RECALC=1, ALGORITHM=INPLACE, LOCK=NONE;
STATS_PERSISTENT指定是否为InnoDB表启用持久统计信息。值DEFAULT 由innodb_stats_persistent设置。值1启用表的持久统计信息,而值0禁用该功能。为单个表启用持久统计信息后,请在加载表数据后使用ANALYZE table计算统计信息。
STATS_SAMPLE_PAGES指定在例如通过ANALYZE TABLE操作为索引列计算基数和其他统计信息时要采样的索引页数。
STATS_AUTO_RECALC指定是否自动重新计算持久统计信息。值DEFAULT使表的持久统计设置由innodb_stats_auto_recalc设置确定。如果值为1,则当10%的表数据发生更改时,将重新计算统计信息。值0阻止自动重新计算表。使用值0时,在对表进行实质性更改后,使用ANALYZE TABLE重新计算统计信息。
指定字符集
ALTER TABLE tbl_name CHARACTER SET = charset_name, ALGORITHM=INPLACE, LOCK=NONE;
如果新字符编码不同,则重建表。
转换字符集
ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name, ALGORITHM=COPY;
如果新字符编码不同,则重建表。
优化表
OPTIMIZE TABLE tbl_name;
优化表格,使用INPLACE(5.6.17后),但不支持ALGORITHM和LOCK的语法。但是有FULLTEXT索引的表不能够使用INPLACE。
FORCE使用选项 重建表
ALTER TABLE tbl_name FORCE, ALGORITHM=INPLACE, LOCK=NONE;
ALGORITHM=INPLACE从 MySQL 5.6.17 开始 使用。表有FULLTEXT 索引时不支持使用ALGORITHM=INPLACE。
执行“空”重建
ALTER TABLE tbl_name ENGINE=InnoDB, ALGORITHM=INPLACE, LOCK=NONE;
从 MySQL 5.6.17 开始使用ALGORITHM=INPLACE。表有FULLTEXT 索引时不支持使用ALGORITHM=INPLACE。
重命名表
ALTER TABLE old_tbl_name RENAME TO new_tbl_name, ALGORITHM=INPLACE, LOCK=NONE;
重命名表,不会执行copy操作。
参考:https://dev.mysql.com/doc/refman/5.7/en/innodb-online-ddl-operations.html#online-ddl-primary-key-operations