故障分析

您所在的位置:网站首页 主键唯一性检查 故障分析

故障分析

2024-07-10 11:54| 来源: 网络整理| 查看: 265

作者:胡呈清

爱可生 DBA 团队成员,擅长故障分析、性能优化,个人博客:https://www.jianshu.com/u/a95ec11f67a8,欢迎讨论。

本文来源:原创投稿

*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

最近遇到一个故障:单主模式5节点 MGR 集群,在使用 mysqlshell 导入数据时,所有secondary节点报错唯一键冲突退出集群。最终得到的结论是:mysqlshell importTable() 导入数据时会做 SET unique_checks=0 操作,在满足一定条件时会导致唯一键约束失效,主库插入了重复的数据,但从库会插入失败从而报错。下面我们就来聊聊这是怎么回事。

unique_checks=0 的原理(会导致唯一键约束失效吗?)

看看官方文档是怎么描述的:

If you have UNIQUE constraints on secondary keys, you can speed up table imports by temporarily turning off the uniqueness checks during the import session: SET unique_checks=0; … SQL import statements … SET unique_checks=1; For big tables, this saves a lot of disk I/O because InnoDB can use its change buffer to write secondary index records in a batch. Be certain that the data contains no duplicate keys.

对大数据量的导入,无论是 sql 文件还是 csv 文件,如果表中有唯一索引,我们可以通过 SET unique_checks=1; 来加快导入速度。这里用到的是 change buffer 的原理:

change buffer 的作用对象是普通二级索引,当插入、修改、删除二级索引记录时,即使数据不在 innodb buffer pool 中,也不需要先把数据从磁盘读取到内存。只需要在 change buffer 中完成 DML 操作,下次读取时才会从磁盘读取到内存,并与 change buffer 进行 merge,从而得到正确的数据。这个功能减少了 DML 时的随机 IO。

这里要注意对象是普通二级索引,唯一索引为什么不行?当执行 DML 时,数据不在内存中,为了保证唯一性,必须先从磁盘读取数据,这个随机 IO 是无法避免的,change buffer 失去了其作用,因此对唯一索引无效。

但是 unique_checks=0 让 change buffer 重新对唯一索引有效了。文档还有句暧昧的描述:“Be certain that the data contains no duplicate keys.”(你需要自己确保数据不包含重复值)。这会让唯一键约束失效吗?再让我们看看文档对于 unique_checks 系统变量的描述:

If set to 0, storage engines are permitted to assume that duplicate keys are not present in input data. If you know for certain that your data does not contain uniqueness violations, you can set this to 0 to speed up large table imports to InnoDB. Setting this variable to 0 does not require storage engines to ignore duplicate keys. An engine is still permitted to check for them and issue duplicate-key errors if it detects them.

至始至终没有出现“不进行唯一性检查”的字眼,写文档的人真是狡猾。要搞清楚这个问题,我们还得回到 change buffer 的原理:change buffer 无法支持唯一索引,但是 unique_checks=0 让 change buffer 重新对唯一索引有效。结合文档两个描述,我们作出如下假设:

如果 set unique_checks=0; DML操作的数据,如果主键和唯一索引在 innodb buffer pool 中,则可以通过内存中的数据进行唯一性检测,这也是我们在测试中都会遇到即使 set unique_checks=0 也不能插入重复数据;但如果 DML 操作的数据如果不在 innodb buffer pool 中,则不会通过读取磁盘上的主键、唯一索引进行唯一检测,此时就和普通的二级索引一样,直接在 change buffer 完成数据写入,减少磁盘 IO。 验证 1. 用 sysbench 造点数据 sysbench /usr/local/share/sysbench/oltp_read_write.lua --mysql-host=127.0.0.1 \ --mysql-port=3309 --mysql-user=root --mysql-password=root \ --mysql-db=sbtest --tables=4 --table-size=1000000 --report-interval=3 --threads=8 --time=300 prepare 2. 再创建一张表,并导入一些数据 CREATE TABLE `t` ( `id` int(11) NOT NULL AUTO_INCREMENT, `a` int(11) NOT NULL, `k` int(11) NOT NULL DEFAULT '0', `c` char(120) COLLATE utf8mb4_bin NOT NULL DEFAULT '', `pad` char(60) COLLATE utf8mb4_bin NOT NULL DEFAULT '', PRIMARY KEY (`id`), KEY `k_1` (`k`), unique key `a` (`a`) ); insert into t(a,k,c,pad) select * from sbtest1 where id set session unique_checks=0; Query OK, 0 rows affected (0.04 sec) mysql> insert into t(a,k,c,pad) values(1,439502,'59488447928-69619891934-66520244141-26804756589-33623161608-43445073345-17979281186-83118017446-98119924781-27868548476','0000'); Query OK, 1 row affected (0.01 sec)

可以看到成功插入了重复数据(这里用where a=1 等值查询只会输出一行结果,因此用 where a select id,a from t where a



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3