MySQL · 捉虫动态 · ALTER IGNORE TABLE导致主备不一致

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 背景 我们知道当一张表的某个字段存在重复值时,这个字段没办法直接加UNIQUE KEY,但是MySQL提供了一个 ALTER IGNORE TABLE的方式,可以忽略修改表结构过程中出现的错误,但是要忽略UNIQUE重复值,就需要打开old_alter_table,也就是拷贝表的方式来ALTER

背景

我们知道当一张表的某个字段存在重复值时,这个字段没办法直接加UNIQUE KEY,但是MySQL提供了一个 ALTER IGNORE TABLE的方式,可以忽略修改表结构过程中出现的错误,但是要忽略UNIQUE重复值,就需要打开old_alter_table,也就是拷贝表的方式来ALTER TABLE。

例如这样:

CREATE TABLE t1(c1 int) ENGINE = InnoDB;
INSERT INTO t1 VALUES (1), (1);
SET old_alter_table=1;
ALTER IGNORE TABLE t1 ADD UNIQUE (c1);

但是如果你是 MySQL 5.5 主备环境,你会发现备库收到这个DDL后,SQL THREAD 会给你一个无情的报错:

'Error 'Duplicate entry '1' for key 'c1'' on query.
Default database: 'test'. Query: 'ALTER IGNORE TABLE t1 ADD UNIQUE (c1)''

原因

这是为什么呢?

其实关键问题就是这个SQL要执行成功,必须保证 old_alter_table 打开,但是 MySQL 的 SET 语句并不参与复制,因此备库只收到了一个 ALTER IGNORE TABLE,而没有先打开 old_alter_table,因此备库用的不是整表拷贝的方法来重建表,因而无法执行成功。

解决

那我们怎么解决这个问题呢,也很简单,只要备库Slave线程也用 old_alter_table=1 来执行 ALTER IGNORE TABLE就好了。

本质上就是 mysql_alter_table() 中需要让need_copy_table= ALTER_TABLE_DATA_CHANGED(old_alter_table=1),而不是need_copy_table= ALTER_TABLE_INDEX_CHANGED(old_alter_table=0)。

因此我们只要在mysql_alter_table()函数中判断该用哪种算法的时候,给出一个可以干预的变量,让Slave线程在需要的时候可以按need_copy_table= ALTER_TABLE_DATA_CHANGED执行。

原来的代码:

   if ((thd->variables.old_alter_table
       || (table->s->db_type() != create_info->db_type)
 #ifdef WITH_PARTITION_STORAGE_ENGINE
       || partition_changed
 #endif
      )
     need_copy_table= ALTER_TABLE_DATA_CHANGED;

我们加上判断 (‘是否启用Slave自动用 ALTER_TABLE_DATA_CHANGED 方式做ALTER IGNORE TABLE’ && thd->slave_thread && ignore),就可以在我们打开控制变量的时候,强制让Slave线程用 old_alter_table=1 的方式来执行 ALTER IGNORE TABLE。

   if ((thd->variables.old_alter_table ||
        ('是否启用Slave自动用 ALTER_TABLE_DATA_CHANGED 方式做ALTER IGNORE TABLE' &&
         thd->slave_thread && ignore))
       || (table->s->db_type() != create_info->db_type)
 #ifdef WITH_PARTITION_STORAGE_ENGINE
       || partition_changed
 #endif
      )
     need_copy_table= ALTER_TABLE_DATA_CHANGED;


相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
25天前
Mybatis+mysql动态分页查询数据案例——测试类HouseDaoMybatisImplTest)
Mybatis+mysql动态分页查询数据案例——测试类HouseDaoMybatisImplTest)
20 1
|
25天前
|
Java 关系型数据库 数据库连接
Mybatis+MySQL动态分页查询数据经典案例(含代码以及测试)
Mybatis+MySQL动态分页查询数据经典案例(含代码以及测试)
24 1
|
25天前
Mybatis+mysql动态分页查询数据案例——条件类(HouseCondition)
Mybatis+mysql动态分页查询数据案例——条件类(HouseCondition)
15 1
|
25天前
Mybatis+mysql动态分页查询数据案例——分页工具类(Page.java)
Mybatis+mysql动态分页查询数据案例——分页工具类(Page.java)
21 1
|
25天前
Mybatis+mysql动态分页查询数据案例——房屋信息的实现类(HouseDaoMybatisImpl)
Mybatis+mysql动态分页查询数据案例——房屋信息的实现类(HouseDaoMybatisImpl)
21 2
|
25天前
Mybatis+mysql动态分页查询数据案例——工具类(MybatisUtil.java)
Mybatis+mysql动态分页查询数据案例——工具类(MybatisUtil.java)
15 1
|
25天前
|
Java 数据库连接 mybatis
Mybatis+mysql动态分页查询数据案例——Mybatis的配置文件(mybatis-config.xml)
Mybatis+mysql动态分页查询数据案例——Mybatis的配置文件(mybatis-config.xml)
14 1
|
25天前
Mybatis+mysql动态分页查询数据案例——配置映射文件(HouseDaoMapper.xml)
Mybatis+mysql动态分页查询数据案例——配置映射文件(HouseDaoMapper.xml)
14 1
|
25天前
Mybatis+mysql动态分页查询数据案例——房屋信息的接口(IHouseDao)
Mybatis+mysql动态分页查询数据案例——房屋信息的接口(IHouseDao)
12 1
|
30天前
|
Java 关系型数据库 MySQL
Mybatis+MySQL动态分页查询数据经典案例
Mybatis+MySQL动态分页查询数据经典案例
18 0
Mybatis+MySQL动态分页查询数据经典案例

相关产品

  • 云数据库 RDS MySQL 版