从模拟数据到场景复现,剖析 MySQL Online DDL 异常报错之谜

云掣YunChe3个月前最新动态200

本文从模拟数据到场景复现,深入浅出的分享了 MySQL 在线 DDL 变更误触报错的原因分析和解决方案,以减少或避免在Online DDL操作中误触发异常错误,提高数据库变更的成功率,希望能对遇到相似问题的客户起到一定的帮助。云掣专注于可观测运维,为您的数字化转型保驾护航~

前言

业务执行一条 alter table table_name engine=innodb 失败了很多次,一直无法执行成功,报错 ERROR 1062 (23000): Duplicate entry xxx for key 'xxx',在官方文档中也提到过,Online DDL 期间可能会出现 ERROR 1062 (23000): Duplicate entry 异常,但是没有详细说明,什么情况下会触发。业务执行 DDL 的时候,一直没有成功,意味着距离找到答案不远了。

When running an in-place online DDL operation, the thread that runs the ALTER TABLE statement applies an online log of DML operations that were run concurrently on the same table from other connection threads. When the DML operations are applied, it is possible to encounter a duplicate key entry error (ERROR 1062 (23000): Duplicate entry), even if the duplicate entry is only temporary and would be reverted by a later entry in the online log. This is similar to the idea of a foreign key constraint check in InnoDB in which constraints must hold during a transaction.

https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-limitations.html

1. 模拟现场

1.1 测试表结构

CREATE TABLE `ddl_test` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NOT NULL,
  `channel_id` tinyint(4) NOT NULL,
  `version` bigint(20) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `user_info` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unq_index` (`user_id`,`channel_id`,`version`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;


1.2 制造测试数据

mysql_random_data_load 是使用 Go 语言开发的 MySQL 随机造数工具,可从下方链接中直接下载编译完成的二进制程序。

下载地址:mysql_random_data_load GitHub

08a7c9c1106c664cf3dfc5e3f14c1182.png

下载对应系统版本的文件,开箱即用。

# 解压后会得到一个二进制程序
tar -zxvf mysql_random_data_load_0.1.12_Linux_x86_64.tar.gz
# 验证
./mysql_random_data_load --help


造数命令模版:

mysql_random_data_load -h127.0.0.1 -u'用户' -p'密码' --max-threads=线程数 库名 表名 造数多少行

造数工具准备好了,现在需要制造一些测试数据,便于观测现象。

mysql_random_data_load -h127.0.0.1 -u'test' -p --max-threads=10 test ddl_test 2000000

1.3 场景复现

截图_20250114173810.png

让人疑惑的是,Session 1 第二次写入并没有成功,为什么会导致 DDL 执行失败呢?

2. 原因分析

经过源码分析,发现 MySQL Online DDL 期间所有的写入都会记录到增利日志中,增量日志是通过聚簇索引(主键)来校验唯一性,只要主键不冲突后就直接写入到增量日志中,然后再依次写唯一索引、二级索引。

image.png

此时唯一索引由于违反约束,执行失败,抛出异常,增量日志这里也没有进行回滚,造成在 Online DDL 合并阶段,违反唯一索引的记录会被合并到表里,造成 DDL 执行失败。

image (1).png

3. 如何解决

了解到业务是一个并发写入的场景,会偶发导致重复写入的问题,定位到业务场景后,通过降低了并发,减少了重复写入。最后 DDL 执行成功。如果遇到该问题,建议先定位问题是由于哪些 SQL 造成的,然后和业务侧配合规避掉这个异常。

4. 误导报错

经过测试在 MySQL 5.7.17 版本复现该问题的时候,会出现一个误导报错。虽然是由 unq_index 约束造成的,在 DDL 会话里面,会直接报错主键的值,并且这个自增主键值不存在,因为已经被回滚了,回滚后自增主键不会重新分配了,会让用户一头雾水。

root@mysql  [deom]>alter table ddl_test engine=innodb, ALGORITHM=INPLACE, LOCK=NONE;
ERROR 1062 (23000): Duplicate entry '200006' for key 'PRIMARY'

后记

经过测试,该问题在最新的长期支持版本 MySQL 8.4 中依然存在。

云掣专注于可观测运维,致力解决企业上云难、用云难、管云难三大问题。基于云数据库提供7*24小时保障服务,提供开发支持、数据库体系规范、持续优化、数据库架构支持,保障企业数据库高效稳定运行。全面提升企业的运维效率和稳定性,助力企业完成云时代的数字化转型,满足客户在数据库管理和云迁移方面的多样化需求!



相关文章

高效安全迁移:PG高可用集群实战方案深度解析

高效安全迁移:PG高可用集群实战方案深度解析

PostgreSQL是一个开源的数据库管理系统,相比于其他开源数据库系统,PostgreSQL有更加丰富的数据类型和可扩展性,并因此被广泛采用。在实际工作中,若企业业务需求变动,则有可能面临PG高可用...

袋鼠云港口数智化解决方案发布,数智引领,加速“智变”

袋鼠云港口数智化解决方案发布,数智引领,加速“智变”

2023年12月,交通运输部印发《关于加快智慧港口和智慧航道建设的意见》,《意见》贯穿了“3条主线”,其中最首要的主线是“数字化”,数字化是基础,必须通过数字赋能建设、生产、运营、管理、服务的全要素、...

袋鼠云秋季发布会圆满落幕,AI驱动让生产力数智化

袋鼠云秋季发布会圆满落幕,AI驱动让生产力数智化

在当今时代,AI 的发展如汹涌浪潮,其速度之快超越了任何历史时期。它以前所未有的迅猛之势,渗入到各个领域的不同场景之中,悄然重塑着商业模式与人们的生活方式。在 AI 逐渐成为企业基础属性的背景下,袋鼠...

初识MySQL数据库

初识MySQL数据库

数据库首先提问,按照常理来说,什么是数据库呢?不少人想到的一点就是,不就是数据的集合吗?是的,数据库从数据存储方面确实只是数据的集合,但是数据库不只是为了集合数据而存在。如果是为了集合数据,像我们磁盘...

阿里云再度携手袋鼠云,重磅联合发布ACOS统一运维监控平台

阿里云再度携手袋鼠云,重磅联合发布ACOS统一运维监控平台

1月13日,袋鼠云旗下数据化运维子公司云掣科技与阿里云再度签署战略合作协议,阿里云智能云原生应用平台负责人丁宇(花名:叔同)、阿里云云原生PaaS负责人张军(花名:游骥)、阿里云智能云原生可观测负责人...

袋鼠云CEO宁海元:打通数智基建到应用的通路,让数据不再“躺灰” | 数据猿专访

袋鼠云CEO宁海元:打通数智基建到应用的通路,让数据不再“躺灰” | 数据猿专访

一家大型制造企业的老板最近心情颇为复杂。几年前,企业投入巨资构建数据存储和治理系统,如今数据确实源源不断地积累,但他发现,这些数据似乎并没有带来预期的业务收益。虽然存储成本逐年攀升,但数据依旧沉睡在系...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。