基本概念

在开始阅读前,先熟悉下以下概念,以便更加方便理解。

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在创建二级索引时退出,则在MySQL服务器恢复时,会删除未完成创建的索引数据。您必须重新运行ALTER TABLE or CREATE 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方式要好:

  1. INPLACE不需要UNDO/REDO log;
  2. 二级索引是预排序的,能够有序地读取;
  3. 不需要更改缓冲区,因为没有二级索引的随机插入;

列操作

下表概述了对列操作的在线 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;

mysql ddl执行权限 mysql dml ddl_mysql ddl执行权限

下表概述了对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操作。