OnLine DDL -- 扩展 VARCHAR 列大小

Posted 我的二狗呢

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OnLine DDL -- 扩展 VARCHAR 列大小相关的知识,希望对你有一定的参考价值。

更详尽的见官方文档: ​​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字符集的情况:

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


其它:

  1. 不支持使用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;

这里没有一一罗列,具体以官方文档为准。







以上是关于OnLine DDL -- 扩展 VARCHAR 列大小的主要内容,如果未能解决你的问题,请参考以下文章

Online ddl 工具之pt-online-schema-change

mysql5.7 online ddl怎么查看进度

online ddl 工具之pt-online-schema-change封装

关于mysql 5.6 哪些操作可以进行online ddl 详解

pt-online-change-ddl(在线ddl)

mysql 5.6 online ddl