更详尽的见官方文档: https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html
同事前几天提了句varchar 255以下的扩大列宽度是不锁表的,再往上扩就是需要加锁的。想起来好像是有这个说法,查了下官方文档确实如此,顺手试验下看看,于是有了下文。
官方文档翻译:
原则:VARCHAR 列所需的长度字节数必须保持不变。对于大小为 0 到 255 个字节的 VARCHAR 列,需要一个长度字节来对值进行编码。对于大小为 256 字节或更多的 VARCHAR 列,需要两个长度字节。
因此,IN-PLACE ALTER TABLE 仅支持将 VARCHAR 列大小从 0 增加到 255 字节,或从 256 字节增加到更大的大小。
IN-PLACE ALTER TABLE 不支持将 VARCHAR 列的大小从小于 256 字节增加到等于或大于 256 字节的大小。在这种情况下,所需的长度字节数从 1 变为 2,例如从varchar(255)改为varchar(256)这种情况下就得使用 ALGORITHM=COPY。
注意: VARCHAR 列的字节长度取决于字符集的字节长度(也就是说latin1和utf8和utf8mb4是有区别的)。
看下我们最常见的UTF8字符集的情况:
代码语言:javascript复制CREATE TABLE `tb1` (
`a` int(10) unsigned NOT NULL AUTO_INCREMENT,
`b` varchar(10) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
上面的表结构中,b列是定义为utf8,占3位,也就是我们要做到无锁扩展,最大只能到 255/3 约等于85 这个宽度。
-- 重置下b列长度
MySQL [test]> ALTER TABLE tb1 CHANGE COLUMN b b VARCHAR(10);
MySQL [test]> ALTER TABLE tb1 CHANGE COLUMN b b VARCHAR(85), ALGORITHM=INPLACE, LOCK=NONE;
-- 重置下b列长度
MySQL [test]> ALTER TABLE tb1 CHANGE COLUMN b b VARCHAR(10);
MySQL [test]> ALTER TABLE tb1 CHANGE COLUMN b b VARCHAR(86), ALGORITHM=INPLACE, LOCK=NONE;
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.
再看看utf8mb4字符集的varchar扩展长度的情况:
代码语言:javascript复制CREATE TABLE `tb5` (
`a` int(10) unsigned NOT NULL AUTO_INCREMENT,
`b` varchar(10) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
上面的表结构中,b列是定义为 utf8mb4 ,占4位,也就是我们要做到无锁扩展,最大只能到 255/4 约等于 63 这个宽度。
-- 重置下b列长度
MySQL [test]> ALTER TABLE tb5 CHANGE COLUMN b b VARCHAR(10);
MySQL [test]> ALTER TABLE tb5 CHANGE COLUMN b b VARCHAR(40), ALGORITHM=INPLACE, LOCK=NONE;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
-- 重置下b列长度
MySQL [test]> ALTER TABLE tb5 CHANGE COLUMN b b VARCHAR(10);
MySQL [test]> ALTER TABLE tb5 CHANGE COLUMN b b VARCHAR(63), ALGORITHM=INPLACE, LOCK=NONE;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
-- 重置下b列长度
MySQL [test]> ALTER TABLE tb5 CHANGE COLUMN b b VARCHAR(10);
MySQL [test]> ALTER TABLE tb5 CHANGE COLUMN b b VARCHAR(64), ALGORITHM=INPLACE, LOCK=NONE; ---> 改为64这里报错了
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.
再看看latin1字符集的varchar扩展长度的情况(255及以下):
代码语言:javascript复制CREATE TABLE `tb2` (
`a` int(10) unsigned NOT NULL AUTO_INCREMENT,
`b` varchar(10) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- 重置下b列长度
MySQL [test]> ALTER TABLE tb2 CHANGE COLUMN b b VARCHAR(10);
MySQL [test]> ALTER TABLE tb2 CHANGE COLUMN b b VARCHAR(128), ALGORITHM=INPLACE, LOCK=NONE;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
-- 重置下b列长度
MySQL [test]> ALTER TABLE tb2 CHANGE COLUMN b b VARCHAR(10);
MySQL [test]> ALTER TABLE tb2 CHANGE COLUMN b b VARCHAR(255), ALGORITHM=INPLACE, LOCK=NONE;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
-- 重置下b列长度
MySQL [test]> ALTER TABLE tb2 CHANGE COLUMN b b VARCHAR(10);
MySQL [test]> ALTER TABLE tb2 CHANGE COLUMN b b VARCHAR(256), ALGORITHM=INPLACE, LOCK=NONE; ---> 改为256这里报错了
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported.
Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.
再看看latin1字符集的varchar扩展长度的情况(256往以上扩展):
代码语言:javascript复制CREATE TABLE `tb4` (
`a` int(10) unsigned NOT NULL AUTO_INCREMENT,
`b` varchar(256) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- 重置下b列长度
MySQL [test]> ALTER TABLE tb4 CHANGE COLUMN b b VARCHAR(256);
MySQL [test]> ALTER TABLE tb4 CHANGE COLUMN b b VARCHAR(1024), ALGORITHM=INPLACE, LOCK=NONE;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
-- 重置下b列长度
MySQL [test]> ALTER TABLE tb4 CHANGE COLUMN b b VARCHAR(256);
MySQL [test]> ALTER TABLE tb4 CHANGE COLUMN b b VARCHAR(4096), ALGORITHM=INPLACE, LOCK=NONE;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
再看看latin1字符集的varchar扩展长度的情况(255以下往256扩展):
代码语言:javascript复制CREATE TABLE `tb3` (
`a` int(10) unsigned NOT NULL AUTO_INCREMENT,
`b` varchar(252) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- 重置下b列长度
MySQL [test]> ALTER TABLE tb3 CHANGE COLUMN b b VARCHAR(252);
MySQL [test]> ALTER TABLE tb3 CHANGE COLUMN b b VARCHAR(255), ALGORITHM=INPLACE, LOCK=NONE;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
-- 重置下b列长度
MySQL [test]> ALTER TABLE tb3 CHANGE COLUMN b b VARCHAR(252);
MySQL [test]> ALTER TABLE tb3 CHANGE COLUMN b b VARCHAR(256), ALGORITHM=INPLACE, LOCK=NONE; ---> 改为256这里报错了
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported.
Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.
再看看latin1字符集的varchar扩展长度的情况(255及以下的扩展):
代码语言:javascript复制CREATE TABLE `tb2` (
`a` int(10) unsigned NOT NULL AUTO_INCREMENT,
`b` varchar(10) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- 重置下b列长度
MySQL [test]> ALTER TABLE tb2 CHANGE COLUMN b b VARCHAR(10);
MySQL [test]> ALTER TABLE tb2 CHANGE COLUMN b b VARCHAR(128), ALGORITHM=INPLACE, LOCK=NONE;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
-- 重置下b列长度
MySQL [test]> ALTER TABLE tb2 CHANGE COLUMN b b VARCHAR(10);
MySQL [test]> ALTER TABLE tb2 CHANGE COLUMN b b VARCHAR(255), ALGORITHM=INPLACE, LOCK=NONE;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
-- 重置下b列长度
MySQL [test]> ALTER TABLE tb2 CHANGE COLUMN b b VARCHAR(10);
MySQL [test]> ALTER TABLE tb2 CHANGE COLUMN b b VARCHAR(256), ALGORITHM=INPLACE, LOCK=NONE; ---> 改为256这里报错了
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported.
Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.
再看看latin1字符集的varchar扩展长度的情况(256往以上扩展):
代码语言:javascript复制CREATE TABLE `tb4` (
`a` int(10) unsigned NOT NULL AUTO_INCREMENT,
`b` varchar(256) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- 重置下b列长度
MySQL [test]> ALTER TABLE tb4 CHANGE COLUMN b b VARCHAR(256);
MySQL [test]> ALTER TABLE tb4 CHANGE COLUMN b b VARCHAR(1024), ALGORITHM=INPLACE, LOCK=NONE;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
-- 重置下b列长度
MySQL [test]> ALTER TABLE tb4 CHANGE COLUMN b b VARCHAR(256);
MySQL [test]> ALTER TABLE tb4 CHANGE COLUMN b b VARCHAR(4096), ALGORITHM=INPLACE, LOCK=NONE;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
其它:
- 不支持使用INPLACE方式 ALTER TABLE 减小 VARCHAR 大小。减小 VARCHAR大小必须使用ALGORITHM=COPY
下面的几个操作也是不锁的,
ALTER TABLE tbl CHANGE old_col_name new_col_name data_type, ALGORITHM=INPLACE, LOCK=NONE;
ALTER TABLE tbl_name DROP COLUMN column_name, ALGORITHM=INPLACE, LOCK=NONE;
ALTER TABLE table AUTO_INCREMENT=next_value, ALGORITHM=INPLACE, LOCK=NONE;
ALTER TABLE t1 DROP COLUMN c2, ALGORITHM=INPLACE, LOCK=NONE;
这里没有一一罗列,具体以官方文档为准。