暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

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

原创 凡尘dba 2023-11-26
336
根据之前的文章 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,业务也基本不会受到影响。



全文完,希望可以帮到正在阅读的你,如果觉得有帮助,可以分享给你身边的朋友,同事,你关心谁就分享给谁,一起学习共同进步~~~

❤ 欢迎关注我的公众号【凡尘读书楼】,一起学习新知识!
————————————————————————————
公众号:凡尘读书楼
墨天轮:https://www.modb.pro/u/399450
知识星球 :凡尘dba人生有限公司
————————————————————————————

最后修改时间:2024-07-07 19:14:33
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论