一、问题:
MySQL5.7.38 主从架构,主节点唯一索引上(唯一索引不是主键)有重复值,全部从节点报 1062,SQL 线程状态异常,根据 SQL 线程报的 binlog 位置点,insert 数据时有重复值,插入失败
二、原因:
unique_checks=0 时导致,在 bug(106121)列表中官方解释的原因:该参数关闭,维护唯一索引时,不会进行物理读,只会进行内存读,来确保唯一索引的唯一性,即如果内存中有冲突数据就报 1062,如果内存中没有冲突数据插入成功,不会进行 io 来将唯一索引相关的数据页拉取到内存。
官方的回复“IMHO this is not a bug”,我理解的意思“不要你觉得,我要我觉得,我就是这么玩的”。
三、故障解决方案:
一、临时解决方案
恢复主从:
在从节点开启会话
set sql_log_bin=0
删除表的唯一索引
重新启动复制线程
缺点是:不能够解决数据重复的问题,切换主从后会面临更多重复数据的问题,如果从节点接收查请求且使用到了原唯一索引的字段,那 sql 效率会严重下降,但是可以解决主从复制停止的问题
二、永久解决方案
业务自己去重,不要插入重复数据
参数 unique_checks 保持为 1
关于重复的业务数据:与业务交流,确定重复数据的处理方式
四、复现步骤:
1. 表结构:
 mysql> create database wl;mysql> show create table wl.lgf\G*************************** 1. row ***************************       Table: lgfCreate Table: CREATE TABLE `lgf` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `k` int(11) NOT NULL DEFAULT '0',  `c` char(120) NOT NULL DEFAULT '',  `pad` char(60) NOT NULL DEFAULT '',  PRIMARY KEY (`id`),  UNIQUE KEY `c` (`c`,`pad`)) ENGINE=InnoDB AUTO_INCREMENT=2147483647 DEFAULT CHARSET=utf8
       复制代码
 
Python 生成随机数据,插入表,并另起会话观察总数据量约 10w 条左右(保证聚簇索引中的前边的数据与后边的数据所在的叶子节点的页相差很远):
 rand.pyimport randomimport oswhile True:    i=str(random.randint(1000,8000000))    a=str(random.randint(1000000000000000,8000000000000000))    b=str(random.randint(1000000000000000,8000000000000000))    c=str(random.randint(100000,800000))    sql="insert ignore into lgf(id,k,c,pad) values(%s,%s,%s,%s) " % (i,c,a,b)    os.system('mysql -uroot -p123456 -h127.0.0.1 -P3306 -e "use wl;%s"' % (sql))
       复制代码
 2. 查询数据:
 查询前10条数据:mysql> select * from wl.lgf order by id limit 10;+------+--------+------------------+------------------+| id   | k      | c                | pad              |+------+--------+------------------+------------------+| 1058 | 162327 | 1693367460515515 | 4503256156555111 || 1072 | 581438 | 7079984640802065 | 3180334749170868 || 1139 | 160022 | 5072986485096872 | 4163430310554381 || 1193 | 780611 | 4790797228737408 | 2940698105313885 || 1234 | 395757 | 4904177529354516 | 4353197763651083 || 1243 | 725513 | 5525166443023382 | 5731401212245669 || 1262 | 749163 | 1132694876665847 | 5159069792931202 || 1280 | 415220 | 2770815803363126 | 3979264947141008 || 1316 | 329253 | 6088415865037450 | 6035685143204331 || 1360 | 403078 | 3344825394389018 | 7962994492618902 |+------+--------+------------------+------------------+10 rows in set (0.00 sec)id=1360 c=3344825394389018 pad=7962994492618902
       复制代码
 3. 拼接 SQL
c 与 pad 的值与 id=1360 值相等,id=1000000000(表中无该 id 行)
 insert into wl.lgf(id,c,pad) values(10000000,'3344825394389018','7962994492618902') ;
       复制代码
 4. 重启 mysqld
目的是清除缓存 为了清空 MySQL 缓存容,还可结合以下几个参数 修改 my.cnf 文件,重启 MySQL 实例
5. 重新插入重复唯一索引数据:
 mysql> set unique_checks=0;
mysql> use wl
mysql> insert into wl.lgf(id,c,pad) values(10000000,'3344825394389018','7962994492618902') ;Query OK, 1 row affected (0.00 sec)
       复制代码
 6. 查询:force index 指定主键查询数据
 mysql> select * from wl.lgf force index(primary) where c='3344825394389018' and pad='7962994492618902';+----------+--------+------------------+------------------+| id       | k      | c                | pad              |+----------+--------+------------------+------------------+|     1360 | 403078 | 3344825394389018 | 7962994492618902 || 10000000 |      0 | 3344825394389018 | 7962994492618902 |+----------+--------+------------------+------------------+2 rows in set (0.37 sec)
       复制代码
 参考文档
MySQL Bugs: #106121: Unique key constraint invalid(https://bugs.mysql.com/bug.php?id=106121)MySQL :: MySQL 8.0 Reference Manual :: 5.1.8 Server System Variables(https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_unique_checks)
Enjoy GreatSQL :)
关于 GreatSQL
GreatSQL 是由万里数据库维护的 MySQL 分支,专注于提升 MGR 可靠性及性能,支持 InnoDB 并行查询特性,是适用于金融级应用的 MySQL 分支版本。
相关链接:   GreatSQL社区	Gitee	GitHub	Bilibili
GreatSQL 社区:
社区博客有奖征稿详情:https://greatsql.cn/thread-100-1-1.html
技术交流群:
微信:扫码添加GreatSQL社区助手微信好友,发送验证信息加群。
评论