真没想到,MySQL8.0 交换分区竟然有这样的 bug

2023年 11月 26日 23.6k 0

根据之前的文章 MySQL 非分区表如何改造成分区表?我们知道分区表很适合用来做大表转储。最近生产做转储变更,发现 MySQL 8.0 交换分区竟然有个bug,即分区表上加字段后再交换分区,会报错 Error Code: 1731. Non matching attribute 'INSTANT COLUMN(s)' between partition and table.复现场景如下:

mysql> CREATE TABLE `TEST` ( `ID` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', `NAME` varchar(200) DEFAULT NULL, `CREATE_TIME` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`CREATE_TIME`,`ID`), KEY `IDX_NAME` (`NAME`), KEY `IDX_ID` (`ID`)) ENGINE=InnoDB AUTO_INCREMENT=2293142 DEFAULT CHARSET=utf8mb4 COMMENT='测试表'PARTITION by RANGE COLUMNS(CREATE_TIME)(PARTITION P202301 VALUES LESS THAN ('2023-02-01') ENGINE = InnoDB, PARTITION P202302 VALUES LESS THAN ('2023-03-01') ENGINE = InnoDB, PARTITION P202303 VALUES LESS THAN ('2023-04-01') ENGINE = InnoDB, PARTITION P202304 VALUES LESS THAN ('2023-05-01') ENGINE = InnoDB, PARTITION P202305 VALUES LESS THAN ('2023-06-01') ENGINE = InnoDB, PARTITION P202306 VALUES LESS THAN ('2023-07-01') ENGINE = InnoDB, PARTITION P202307 VALUES LESS THAN ('2023-08-01') ENGINE = InnoDB, PARTITION P202308 VALUES LESS THAN ('2023-09-01') ENGINE = InnoDB, PARTITION P202309 VALUES LESS THAN ('2023-10-01') ENGINE = InnoDB, PARTITION P202310 VALUES LESS THAN ('2023-11-01') ENGINE = InnoDB, PARTITION P202311 VALUES LESS THAN ('2023-12-01') ENGINE = InnoDB, PARTITION P202312 VALUES LESS THAN ('2024-01-01') ENGINE = InnoDB, PARTITION PMAX VALUES LESS THAN (MAXVALUE) ENGINE = InnoDB);
 mysql> alter table TEST add `ADDRESS` varchar(200) DEFAULT NULL COMMENT '地址';
mysql> CREATE TABLE `TEST_P202301` ( `ID` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', `NAME` varchar(200) DEFAULT NULL COMMENT '名字', `CREATE_TIME` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `ADDRESS` varchar(200) DEFAULT NULL COMMENT '地址', PRIMARY KEY (`CREATE_TIME`,`ID`), KEY `IDX_NAME` (`NAME`), KEY `IDX_ID` (`ID`)) ENGINE=InnoDB AUTO_INCREMENT=2293142 DEFAULT CHARSET=utf8mb4 COMMENT='测试表';

mysql> alter table TEST EXCHANGE PARTITION P202301 WITH TABLE TEST_P202301 without validation;Error Code: 1731. Non matching attribute 'INSTANT COLUMN(s)' between partition and table.

初次看到这个报错关键字 'INSTANT COLUMN(s)' ,就感觉与 MySQL 8.0 秒级加列算法有关系,因为从 MySQL 8.0.12 开始,Online DDL 才开始支持 INSTANT 算法。

使用这个算法进行加列操作,只需修改表的元数据信息,操作瞬间就能完成。不过在 MySQL 8.0.29 之前,列只能添加到表的最后位置。

从 MySQL 8.0.29 开始,则移除了这一限制,新增列可以添加到表的任何位置。

不仅如此,从 MySQL 8.0.29 开始,删列操作也可以使用 INSTANT 算法。

而在 MySQL 5.7,DDL 算法只有 INPLACE 和 COPY,但是出现这个报错,到底应该怎么解决呢?

经过一番研究和查阅资料,我发现可以通过强制拷贝表的命令解决:

alter table TEST ALGORITHM=copy;
alter table TEST EXCHANGE PARTITION P202301 WITH TABLE TEST_P202301 without validation;

但同时,我马上意识到这个 copy 操作存在一个很大的问题,就是表数据量小的时候看似没有问题,但如果数据量较大,锁表时间就会很长影响到业务。

最好的办法是 MySQL 8.0 需要交换分区的表禁止 DDL,但是这谁也不能保证,有没有一种方法绕过去呢?

经过一番思索,我想到 MySQL 5.7 加字段的原理,于是将 MySQL 8.0 分区表加字段改为以下命令:

alter table TEST `ADDRESS` varchar(200) DEFAULT NULL COMMENT '地址' ALGORITHM =INPLACE, LOCK =NONE;

即 MySQL 8.0 分区表未来如果必须加字段,则可以改成 MySQL 5.7 的用法,避开这个 bug,相比于 MySQL 8.0 默认的秒级加列算法 INSTANT,INPLACE 算法的速度虽然会慢点,但是不会阻塞表的dml,业务也基本不会受到影响。

相关文章

Oracle如何使用授予和撤销权限的语法和示例
Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
社区版oceanbase安装
Oracle 导出CSV工具-sqluldr2
ETL数据集成丨快速将MySQL数据迁移至Doris数据库

发布评论