MySQL唯一约束失效深度剖析

news2024/11/24 11:56:06

详细情况:

业务反馈:“用int查出来有两条数据,char类型查出来只有一条数据 ,这几个字段还是uk的 ”(版本MySQL 5.7.25)

表结构如下:
CREATE TABLE test_table (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL ,
  `master_id` int(11) NOT NULL,
  `create_time` datetime NOT NULL ,
  `update_time` datetime NOT NULL ,
  `version_id` int(11) DEFAULT NULL ,
  `device_id` varchar(128) DEFAULT NULL ,
  `resource_type` tinyint(4) NOT NULL,
  `status` tinyint(4) NOT NULL DEFAULT '0',
  `apply_status` tinyint(4) NOT NULL DEFAULT '0',
  `pay_status` tinyint(4) NOT NULL DEFAULT '0',
  `count` int(11) NOT NULL DEFAULT '0',
  `ext` text NOT NULL ,
  `idc_region` varchar(20),
  PRIMARY KEY (`id`),
  UNIQUE KEY `index_user_mid_deviceid_region` (`user_id`,`master_id`,`device_id`,`idc_region`),
  KEY `index_apply_user` (`user_id`) USING BTREE,
  KEY `index_apply_mid` (`master_id`) USING BTREE
) ENGINE=InnoDB;

初步结论:唯一索引未能起到唯一约束作用。

分析

从上面情况来看,有唯一性冲突的数据在表里了,但除了唯一约束的列,其它字段字并不相同,也就是说,两个数据都可能是有效数据,不能删除一条了事,需要确定为什么有唯一索引还能再插入相同值,下次避免同类问题。

询问当时操作的运维同学,这些数据是批量导入的,分析当时binlog,发现导入前关了外键检查和唯一性检查:

SET @@session.foreign_key_checks=0, @@session.unique_checks=0/*!*/;

这两个关闭并不是运维同学手动设置的,是导入工具为了提高导入性能做的默认设置,需要人工保证数据无外键冲突,无唯一键冲突,通常,仅用于对空表导入数据,但本案例中,是对一个已有数据的表导入数据。显然,unique_checks关闭,字面上来看很可能导致重复数据插进去。

但是,当尝试复现时,发现无论怎么unique_checks是开是关,都会检查唯一性,并不能插入数据,因此还有其它条件影响。

深度分析

尝试多种办法,均无法复现,分析对应部分源码:

unique_checks 设置是设置是改变option_bits变量第OPTION_RELAXED_UNIQUE_CHECKS位的值,这个事最终会保存到事务结构trx->check_unique_secondary上:

static Sys_var_bit Sys_unique_checks(//设置参数时影响值
       "unique_checks", "unique_checks",
       SESSION_VAR(option_bits), NO_CMD_LINE,
       REVERSE(OPTION_RELAXED_UNIQUE_CHECKS),
       DEFAULT(TRUE), NO_MUTEX_GUARD, IN_BINLOG);


innobase_trx_init(
    THD*    thd,    /*!< in: user thread handle */
    trx_t*  trx)    /*!< in/out: InnoDB transaction handle */
{
    trx->check_foreigns = !thd_test_options(
        thd, OPTION_NO_FOREIGN_KEY_CHECKS);


    trx->check_unique_secondary = !thd_test_options(
        thd, OPTION_RELAXED_UNIQUE_CHECKS);//最终保存在此


    trx->stats.set(innobase_slow_log_verbose(thd));


    DBUG_VOID_RETURN;
}

然后在检查后续对这个变量做一次转换保存到search_mode 中:

    /* Note that we use PAGE_CUR_LE as the search mode, because then
    the function will return in both low_match and up_match of the
    cursor sensible values */


    if (!thr_get_trx(thr)->check_unique_secondary) {
        search_mode |= BTR_IGNORE_SEC_UNIQUE;  //保存在此
    }

再在 btr_cur_search_to_nth_level 函数中,转换成btr_op= BTR_INSERT_IGNORE_UNIQUE_OP,如下:

    case BTR_INSERT:
        btr_op = (latch_mode & BTR_IGNORE_SEC_UNIQUE)
            ? BTR_INSERT_IGNORE_UNIQUE_OP
            : BTR_INSERT_OP;
        break;

btr_cur_search_to_nth_level 函数中继续向下看,扫描查找是先在buffer pool中找对应的页面,如果找不到,即block =NULL时,且上面的btr_op为BTR_INSERT_IGNORE_UNIQUE_OP时,才会不检查唯一性,直接插入ibuf中,ibuf就是change buffer:

 如果能从buffer pool中找到页面,会直接更新,也不会有问题。从源码上分析来看,只有找不到block的这一个路径,会让唯一约束检查失效,全局搜索代码,未发现有其它入口会不检查唯一性直接插入。关于change buffer作用,介绍的文章很多,分享一个链接:

写缓冲(change buffer),这次彻底懂了!!! - 掘金

根因猜测:

因此,从源码上看,满足以下几个条件可能导致这个问题:

  1. unique_checks=off
  2. 使用了change buffer(使用change buffer的要求同时要满足)
  3. 要更新的页刚好不在buffer pool中,如果在buffer pool中就会直接更新,不走changer buffer,不会有问题,详细见上面的changer buffer说明文章。

复现验证:

既然源码上看存在可能性,那么可尝试构造场景复现。

将buffer pool改到很小的200MB,打开change buffer, 关闭unique_checks,对sbtest1表插入10W条件记录,sbtest1表如下:

CREATE TABLE `sbtest1` (

  `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`,`k`),

  KEY `k_1` (`k`)

) ENGINE=InnoDB AUTO_INCREMENT=100002 DEFAULT CHARSET=utf8;

插一行记录,直接插入违反唯一约束的值会报错:

insert into sbtest1 values(100001,49898,1234567801,'fdsfsafsdfsfsadfffffffffdfsa');

对另外一个表插入100W行,将sbtest1表的buffer pool页面淘汰,一会之后再次插入上面内容成功:

使用数字和字符串查询得到不同结果,与线上问题完全一致,成功复现该bug:

虽然复现了,能插入数据,的确存在了冲突数据,但还有一个小问题,为什么带引号和不带引号结果不一样?

字段c的类型char(120),当带引号是传入值是字符串,会走唯一索引,所以只有一条记录。当不带引号用int查询时, 内部有隐式转换,这个转换会导致唯一索引失效,计划不会走使用这个唯一索引,所以能查出两条。

如何避免此类问题:

检查导入数据工具是否有设置约束参数配置,如果对非空表导入数据,不能去掉相关约束检查,有可能导致数据重复。

可以在导入数据时,手动关闭change buffer,导入完成后再打开。在大批量导入数据时,change buffer并不能优化性能。

补充:当时是用Mydumper导出数据,该工具默认就是foreign_key_checks、unique_checks检查均关闭,且不支持参数设置,那么使用Mydumper导出数据,导入到非空表时,要记得关闭changer buffer。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/614913.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

构建方便残障人士使用的网站 web enhance the accessibility

文章目录 前言检测网站是否符合残障人士使用window版软件edge浏览器插件版 前端开发为残障人士的通用标准img标签a标签字体与颜色显示或隐藏的元素可交互的元素标记元素类别 总结 前言 网站的构建往往会忽略一群特殊的人群&#xff0c;在某些方便存在障碍的网民&#xff0c;比…

Docker镜像管理

Docker 概述 Docker是什么 Docker是一个开源的应用容器引擎&#xff0c;基于go语言开发并遵循了apache2.0协议开源。 Docker是在Linux容器里运行应用的开源工具&#xff0c;是一种轻量级的“虚拟机”。 Docker 的容器技术可以在一台主机上轻松为任何应用创建一个轻量级的、可移…

基于状态的维护(CBM)如何推动设备效率提高?

基于状态的维护&#xff08;Condition-Based Maintenance&#xff0c;CBM&#xff09;是一种先进的维护策略&#xff0c;通过实时监测和分析设备的状态数据&#xff0c;预测设备故障并采取相应的维护措施。CBM基于数据驱动的方法&#xff0c;能够提高设备的可用性、降低维修成本…

PDF怎么转成PPT文件免费?分享几个方法!

PDF文件和PPT文件是常见的两类文件&#xff0c;广泛应用于打工人和学生党之间。每种文件格式都有自己的优势&#xff0c;在不同的情况下使用。PDF格式具有出色的浏览效果&#xff0c;能有效保护文档内容免受随意篡改&#xff0c;而且在传输过程中不会出现乱码问题。然而&#x…

Apifox 发请求时如何自动获取Cookie 和 token

介绍 用户登录到网站或 App 是非常常见的的场景&#xff0c;登录成功后一般会返回登录凭证&#xff08;一般为 Cookie 或者 token&#xff09;&#xff0c;后续其它接口发起请求时会携带 Cookie 或者 token 到服务器进行校验。校验通过&#xff0c;则返回相关的数据&#xff0…

【Linux网络编程】应用层HTTP协议篇

应用层 一、应用层1.1、再谈协议1.2、HTTP协议1.2.1、认识URL1.2.2、urlencode和urldecode1.2.3、HTTP协议格式1.2.4、HTTP的方法1.2.5、HTTP的状态码1.2.6、HTTP常见的Header 二、结合代码理解HTTP通信流程 一、应用层 程序员写的一个个解决我们实际问题, 满足我们日常需求的…

Stable Diffusion原理说明

本文参考&#xff1a;深入浅出讲解Stable Diffusion原理&#xff0c;新手也能看明白 - 知乎 目录 1、Stable Diffusion能做什么&#xff1f; 2、扩散模型&#xff08;Diffusion model&#xff09; &#xff08;1&#xff09;前向扩散&#xff08;Forward Diffusion&#xff…

Simple-BEV:多传感器BEV感知中真正重要的是什么?

文章&#xff1a;Simple-BEV: What Really Matters for Multi-Sensor BEV Perception? 作者&#xff1a;Adam W. Harley &#xff0c; Zhaoyuan Fang&#xff0c;Jie Li&#xff0c;Rares Ambrus &#xff0c; Katerina Fragkiadaki 编辑&#xff1a;点云PCL 代码&#xff1a;…

华为OD机试之查找接口成功率最优时间段(Java源码)

查找接口成功率最优时间段 题目描述 服务之间交换的接口成功率作为服务调用关键质量特性&#xff0c;某个时间段内的接口失败率使用一个数组表示&#xff0c;数组中每个元素都是单位时间内失败率数值&#xff0c;数组中的数值为0~100的整数&#xff0c;给定一个数值(minAverag…

【Web服务应用】Apache配置与应用

Apache配置与应用 一、构建虚拟Web主机1.1httpd服务支持的虚拟主机类型包括以下三种 二、基于域名的虚拟主机三、基于IP地址的虚拟主机四、基于端口的虚拟机五、Apache连接保持六、构建Web虚拟目录与用户授权限制七、日志分割 一、构建虚拟Web主机 虚拟Web主机指的是在同一台服…

手把手教你部署FreeYOLO

作者:Kissrabbit 原文链接: https://zhuanlan.zhihu.com/p/578830729 本章将讲解如何将torch训练好的权重文件转换为ONNX文件&#xff0c;并如何部署回到OpenVINO、TensorRT等框架下。笔者将以自己的FreeYOLO项目为例&#xff0c;来完成本章的内容讲解&#xff0c;相关代码如下…

企业数字化转型转什么?怎么转?这份攻略请收好...

数字化转型&#xff0c;转什么&#xff1f;怎么转&#xff1f;这些问题仍在困扰不少企业&#xff0c;也是每个企业转型升级不得不思考的重要问题。 对此&#xff0c;中关村数字经济产业联盟、元年研究院、《管理会计研究》联合发布了《成就数据驱动型企业 中国企业数字化转型白…

ROS订阅与发布话题

目录 一、新建一个ROS工作空间并创建功能包 二、创建一个msg消息 三、发布话题 四、订阅话题 前言 Ubuntu18.04 ROS Melodic 一、新建一个ROS工作空间并创建功能包 mkdir -p catkin_ws/src cd ~/catkin_ws/src/ catkin_init_workspace cd ~/catkin_ws/ catkin_make echo &…

USB接口的演变与升级

USB接口是计算机与外部设备之间传输数据的重要接口之一&#xff0c;它的演变和升级经历了多年的发展。本文将详细介绍USB接口的发展历程、应用领域、标准化进程以及未来趋势。 USB接口最早出现在1994年&#xff0c;当时是由英特尔公司、微软公司和惠普公司共同开发的。这个接口…

React中useEffect的源码解读

对源码的解读有利于搞清楚Hooks到底做了什么&#xff0c;如果您觉得useEffect很“魔法”&#xff0c;这篇文章也许对您有些帮助。 本篇博客篇幅有限&#xff0c;只看useEffect&#xff0c;力求简单明了&#xff0c;带您到React Hooks的深处看看 按图索骥找到Hook相关源码&…

JavaWeb之Servlet

1、什么是JavaWeb&#xff1f; Servlet 是 JavaEE 规范之一。规范就是接口 Servlet 就 JavaWeb 三大组件之一。三大组件分别是&#xff1a;Servlet 程序、Filter 过滤器、Listener 监听器。 Servlet 是运行在服务器上的一个 java 小程序&#xff0c;它可以接收客户端发送过来的…

Python plt; ax 设置tick

Python中绘图可以基于plt&#xff1b;也可基于ax 在 Matplotlib 中&#xff0c;Axes 对象&#xff08;常简写为 ax&#xff09;是在图&#xff08;Figure&#xff09;中进行大部分的绘图操作的地方。一个 Axes 对象代表了一个具体的绘图区域。 利用 plt 绘图 简单的图像测试…

继续探索Roop(单张图视频换脸)的各方面:比如喜闻乐见的“加速”

文章目录 &#xff08;一&#xff09;Roop项目的特点&#xff08;二&#xff09;Roop也能加速***&#xff08;三&#xff09;Roop更新和依赖&#xff08;3.1&#xff09;飞速更新&#xff08;3.2&#xff09;依赖问题&#xff08;3.3&#xff09;需要CUDA么 前两天写了&#x1…

如何修复vcruntime140.dll文件?多种解决vcruntime140.dll的方法分享

在使用Windows操作系统时&#xff0c;经常会遇到一些错误提示&#xff0c;比如缺少vcruntime140.dll文件。这个文件是Visual C Redistributable Package的一部分&#xff0c;它负责运行C程序。如果你在运行某些软件或游戏时收到了“缺少vcruntime140.dll文件”的错误提示&#…

电子科技大学计算机系统结构半期考试参考答案

2023 答案-半期试题&#xff08;15分&#xff09; 1、试分析采用哪种设计方案实现求浮点数乘法FPMUL对系统性能提高更大。假定FPMUL操作占整个测试程序执行时间的10%。 一种设计方案是增加专门的FPMUL硬件&#xff0c;可以将FPMUL操作的速度加快到10倍&#…