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,业务也基本不会受到影响。
全文完,希望可以帮到正在阅读的你,如果觉得有帮助,可以分享给你身边的朋友,同事,你关心谁就分享给谁,一起学习共同进步~~~
❤ 欢迎关注我的公众号【凡尘读书楼】,一起学习新知识!
————————————————————————————
公众号:凡尘读书楼
墨天轮:https://www.modb.pro/u/399450
知识星球 :凡尘dba人生有限公司
————————————————————————————