同事前几天提了句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字符集的情况:
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扩展长度的情况:
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及以下):
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往以上扩展):
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扩展):
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及以下的扩展):
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往以上扩展):
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;
这里没有一一罗列,具体以官方文档为准。