【mysql并行批量删除死锁排查】

文章目录

    • 背景
    • 表单和索引结构
    • 原因分析
    • 解决方案

背景

mysql批量删除并插入新数据的场景下,为提高执行效率,使用了多线程并发执行的方式。当然mysql建表时使用了分区(partition)机制,聚焦到我们这次讨论的问题,分区(partition)以及跟案例无关的内容暂且不提。

测试环境并发量不高,简单验证执行ok,预发环境并发量比较高,逻辑验证时,出现了以下错误:


2023-08-03 15:15:17.924 32098 ERROR [] --- [thread-6] druid.sql.Statement                     :149 : {conn-210049, pstmt-220068} execute error. DELETE FROM `tablename_202308`WHERE `date` = 20230803 AND `app_code` = 'APPCODE' AND `referer` = ?AND `target_type` IN (  1, 6, 8, 9, 12, 5)LIMIT 5000;com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transactionat com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:123)at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953)at com.mysql.cj.jdbc.ClientPreparedStatement.execute(ClientPreparedStatement.java:370)at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_execute(FilterChainImpl.java:3461)

mysql死锁了:Deadlock found,通过查看mysql死锁日志“命令: show engine innodb status;”,得到以下内容:

------------------------
LATEST DETECTED DEADLOCK
------------------------
2023-08-03 15:15:17 140057117718272
*** (1) TRANSACTION:
TRANSACTION 701477003, ACTIVE 1 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 171 lock struct(s), heap size 24784, 10001 row lock(s), undo log entries 5000
MySQL thread id 1136049, OS thread handle 140057034860288, query id 753710384 172.30.184.173 zykj updating
DELETE FROM `tablename_202308`WHERE `date` = 20230803 AND `app_code` = 'APPCODE' AND `referer` = 'happy'AND `target_type` IN (  1, 6, 8, 9, 12, 5) LIMIT 5000*** (1) HOLDS THE LOCK(S):
RECORD LOCKS space id 234584 page no 6144 n bits 352 index idx_ad_network of table `pre`.`tablename_202308` /* Partition `p14` */ trx id 701477003 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 320: len 4; hex 0134b293; asc  4  ;;1: len 17; hex 3130325f61645f726571756573745f7076; asc 102_ad_request_pv;;2: len 1; hex 06; asc  ;;3: len 8; hex 176969e363f9f00f; asc  ii c   ;;4: len 12; hex 636f6d2e73732e6861707079; asc happy;;*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 234584 page no 2156 n bits 400 index idx_ad_network of table `pre`.`tablename_202308` /* Partition `p14` */ trx id 701477003 lock_mode X locks rec but not gap waiting
Record lock, heap no 97 PHYSICAL RECORD: n_fields 5; compact format; info bits 320: len 4; hex 0134b293; asc  4  ;;1: len 17; hex 3130325f61645f726571756573745f7076; asc 102_ad_request_pv;;2: len 1; hex 05; asc  ;;3: len 8; hex 176969e3c3f9f003; asc  ii     ;;4: len 14; hex 636f6d2e64642e72656164696e67; asc com.dd.reading;;*** (2) TRANSACTION:
TRANSACTION 701477006, ACTIVE 1 sec fetching rows
mysql tables in use 1, locked 1
LOCK WAIT 64 lock struct(s), heap size 8400, 581 row lock(s), undo log entries 290
MySQL thread id 1136048, OS thread handle 140071716505344, query id 753710360 172.30.184.173 zykj updating
DELETE FROM `tablename_202308`WHERE `date` = 20230803 AND `app_code` = 'APPCODE' AND `referer` = 'com.dd.reading'AND `target_type` IN (  1, 6, 8, 9, 12, 5) LIMIT 5000*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 234584 page no 2156 n bits 400 index idx_ad_network of table `pre`.`tablename_202308` /* Partition `p14` */ trx id 701477006 lock_mode X locks rec but not gap
Record lock, heap no 97 PHYSICAL RECORD: n_fields 5; compact format; info bits 320: len 4; hex 0134b293; asc  4  ;;1: len 17; hex 3130325f61645f726571756573745f7076; asc 102_ad_request_pv;;2: len 1; hex 05; asc  ;;3: len 8; hex 176969e3c3f9f003; asc  ii     ;;4: len 14; hex 636f6d2e64642e72656164696e67; asc com.dd.reading;;.... 忽略部分日志Record lock, heap no 333 PHYSICAL RECORD: n_fields 5; compact format; info bits 320: len 4; hex 0134b293; asc  4  ;;1: len 17; hex 3130325f61645f726571756573745f7076; asc 102_ad_request_pv;;2: len 1; hex 05; asc  ;;3: len 8; hex 176969e3c3f9f41d; asc  ii     ;;4: len 14; hex 636f6d2e64642e72656164696e67; asc com.dd.reading;;*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 234584 page no 6144 n bits 352 index idx_ad_network of table `pre`.`tablename_202308` /* Partition `p14` */ trx id 701477006 lock_mode X locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 320: len 4; hex 0134b293; asc  4  ;;1: len 17; hex 3130325f61645f726571756573745f7076; asc 102_ad_request_pv;;2: len 1; hex 06; asc  ;;3: len 8; hex 176969e363f9f00f; asc  ii c   ;;4: len 12; hex 636f6d2e73732e6861707079; asc happy;;*** WE ROLL BACK TRANSACTION (2)

表单和索引结构


CREATE TABLE `tablename_202308` (`ad_rev_record_id` bigint unsigned NOT NULL COMMENT '主键',`app_code` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '',`target_id` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '指标id',`target_type` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '指标类型',`ad_rev_target_id` bigint unsigned NOT NULL COMMENT 'xx主键',`this_qid` varchar(200) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '渠道',`this_lid` varchar(200) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '',`brand` varchar(50) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '品牌',`ad_network` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '广告网络:',`referer` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '',`app_ad_id` varchar(200) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '()',`adcdn_ad_id` varchar(200) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '',`date` int unsigned NOT NULL DEFAULT '0' COMMENT '日期,格式:yyyyMMdd',`value` decimal(14,6) NOT NULL DEFAULT '0.000000' COMMENT '结果',`create_by` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建者',`update_by` bigint unsigned NOT NULL DEFAULT '0' COMMENT '更新者',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`ad_rev_record_id`,`referer`),KEY `idx_date_type` (`date`,`target_type`),KEY `idx_ad_rev_target_id` (`ad_rev_target_id`),KEY `idx_ad_network` (`date`,`target_id`,`ad_network`),KEY `idx_qid` (`date`,`target_id`,`this_qid`,`this_lid`),KEY `idx_ad` (`date`,`target_id`,`app_ad_id`,`ad_network`,`adcdn_ad_id`),KEY `idx_ad_qid` (`date`,`target_id`,`app_ad_id`,`this_qid`,`ad_network`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='精简结果表'
/*!50100 PARTITION BY KEY (referer)
PARTITIONS 20 */

原因分析

从mysql的死锁日志可以看出mysql的删除流程中,会涉及到索引的锁定,索引的删除;
mysql的锁是加在如下位置:

RECORD LOCKS space id 234584 page no 6144 n bits 352 index idx_ad_network of table `pre`.`tablename_202308` /* Partition `p14` */ trx id 701477003 lock_mode X locks rec but not gap

space id 234584 page no 6144 n bits 352 index,
因为我们是事务操作(先删除,后插入),在事务提交前,锁会一直存在。

在我们的case中,两个事务a和b分别持有记录锁A(space id 234584 page no 6144 n bits 352 )和锁B(space id 234584 page no 2156 n bits 400),而又分别去请求锁B(space id 234584 page no 2156 n bits 400)和锁A(space id 234584 page no 6144 n bits 352 ),导致了死锁问题的产生。

重点看下索引:KEY idx_ad_network (date,target_id,ad_network),和删除语句

WHERE `date` = 20230803 AND `app_code` = 'APPCODE' AND `referer` = ?AND `target_type` IN (  1, 6, 8, 9, 12, 5)

该索引(idx_ad_network)不能区分出target_type,所以mysql在删除时选择了锁定所有索引页,而多个线程删除时有顺序的差异,最终导致死锁的产生了。

解决方案

在索引中添加target_type字段,那么mysql在删除锁定分页时,可以根据target_type进行区分,不必锁定所有索引页,来避免死锁产生。
如下更改索引后,多线程并发删除不再有死锁的异常(实际场景时app_code固定值,所有没有添加到索引中。)

CREATE TABLE `tablename_202308` (.... 忽略表字段信息PRIMARY KEY (`ad_rev_record_id`,`referer`),KEY `idx_ad_rev_target_id` (`date`,`referer`,`target_type`,`ad_rev_target_id`),KEY `idx_ad_network` (`date`,`referer`,`target_type`,`target_id`,`ad_network`),KEY `idx_qid` (`date`,`referer`,`target_type`,`target_id`,`this_qid`,`this_lid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='精简结果表'
/*!50100 PARTITION BY KEY (referer)
PARTITIONS 30 */

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

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

相关文章

Redis_主从复制

8. 主从复制 8.1 简介 主从库采用读写分离的方式 读操作:主库、从库都可以处理写操作:首先写到主库执行,然后再将主库同步给从库。 实现读写分离,性能扩展 容灾快速恢复 8.2 主从复制步骤 创建一个目录 ,在root下创建一个m…

hive on tez资源控制

sql insert overwrite table dwintdata.dw_f_da_enterprise2 select * from dwintdata.dw_f_da_enterprise; hdfs文件大小数量展示 注意这里文件数有17个 共计321M 最后是划分为了21个task 为什么会有21个task?不是128M 64M 或者说我这里小于128 每个文件一个map…

(C++)继承

目录 1.继承的概念及定义 1.1继承的概念 1.2继承定义 1.2.1定义格式 1.2.2继承方式和访问限定符 1.2.3继承基类成员访问方式的变化 2.基类和派生类对象赋值转换 3.继承中的作用域 4.派生类的默认成员函数 5.继承与友元 6.继承与静态成员 7.复杂的菱形继承及菱形虚拟…

请简述React是什么?React的主要特点有哪些?React中有哪些主要组件?

1、请简述React是什么? React是一个用于构建用户界面的JavaScript库,它由Facebook开发并开源。React的主要特点是其数据驱动和组件化的设计理念。它允许开发者将复杂的界面分解为简单的组件,并将这些组件以数据流的方式组合在一起&#xff0…

2.0 Python 数据结构与类型

数据类型是编程语言中的一个重要概念,它定义了数据的类型和提供了特定的操作和方法。在 python 中,数据类型的作用是将不同类型的数据进行分类和定义,例如数字、字符串、列表、元组、集合、字典等。这些数据类型不仅定义了数据的类型&#xf…

题目:灾后重建

【题目描述】 B地区在地震过后,所有村庄都造成了一定的损毁,而这场地震却没对公路造成什么影响。但是在村庄重建好之前,所有与未重建完成的村庄的公路均无法通车。换句话说,只有连接着两个重建完成的村庄的公路才能通车&#xff…

cmake常用命令(1)——函数相关

一、function/endfunction cmake中的函数与其他语言相似&#xff0c;表示一个命令集&#xff0c;可以被重复调用。形式如下&#xff1a; function(<name> [<arg1> ...])<commands> endfunction() function&#xff1a;表示函数开始 <name>&#xf…

Nexus npm仓库如何设置同步频率

在 Nexus Repository Manager 中&#xff0c;设置同步频率可以确保你的代理或镜像仓库能够及时获取外部仓库中的最新包。以下是设置同步频率的一般步骤&#xff1a; 登录到 Nexus 管理界面&#xff1a;使用管理员账号登录到 Nexus Repository Manager 的 Web 管理界面。 选择仓…

SpringBoot复习:(24)DeferredImportSelector

功能&#xff1a; 定一一个字符串数组&#xff0c;每个元素都是一个类的全限定名&#xff08;包名类名&#xff09;&#xff0c;把这些类的实例注册到Spring 容器。 一、定义要注册的类&#xff1a; package cn.edu.tju.service;import java.util.Arrays; import java.util.Li…

Android11 设置备用DNS

在Android11 版本的rom 产品开发过程中&#xff0c;遇到一个问题&#xff0c;发现分配的DNS不可用的情况&#xff0c;所以需要设置备用DNS。 直接上代码 //frameworks/base/services/core/java/com/android/server/ConnectivityService //ConnectivityService.java --> //…

【脚踢数据结构】链表(1)

(꒪ꇴ꒪ )&#xff0c;Hello我是祐言QAQ我的博客主页&#xff1a;C/C语言,Linux基础,ARM开发板&#xff0c;软件配置等领域博主&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff0c;让我们成为一个强大的攻城狮&#xff01;送给自己和读者的一句鸡汤&#x1f914;&…

机器学习基础之《特征工程(3)—特征预处理》

一、什么是特征预处理 通过一些转换函数将特征数据转换成更加适合算法模型的特征数据过程 处理前&#xff0c;特征值是数值&#xff0c;处理后&#xff0c;进行了特征缩放 1、包含内容 数值型数据的无量纲化&#xff1a; 归一化 标准化 2、特征预处理API sklearn.preproces…

什么是训练数据?

算法从数据中学习。算法从得到的训练数据中找到关系&#xff0c;形成理解&#xff0c;做出决策&#xff0c;并评估信心。训练数据越好&#xff0c;模型的表现就越好。 实际上&#xff0c;与算法本身一样&#xff0c;训练数据的质量和数量与数据项目的成功有很大关系。 现在&…

Java项目作业~ 通过html+Servlet+MyBatis,完成站点信息的添加功能

需求&#xff1a; 通过htmlServletMyBatis&#xff0c;完成站点信息的添加功能。 以下是站点表的建表语句&#xff1a; CREATE TABLE websites (id int(11) NOT NULL AUTO_INCREMENT,name char(20) NOT NULL DEFAULT COMMENT 站点名称,url varchar(255) NOT NULL DEFAULT ,…

html2canvas截图生成图片并保存到本地的解决方案

html2canvas截图生成图片并保存到本地的解决方案 一、构建HTML容器二、html2canvas截图封装函数避坑指南1.尺寸过大而无法成功生成图片 html2canvas是一款JavaScript插件&#xff0c;能够将网页上的HTML元素转化为Canvas对象&#xff0c;从而可以将网页截图输出为图片或者PDF文…

Go学习第八天

签名 func (a *Account) Sign(message []byte) ([]byte, error) {hash : crypto.Keccak256Hash(message)signature, err : crypto.Sign(hash.Bytes(), a.privateKeyECDSA)if err ! nil {log.Fatal(err)}signMsg : []byte(hexutil.Encode(signature))return signMsg, err }验签…

CentOS7 安装远程桌面

换源 设置镜像源为清华源&#xff1a; sudo sed -e s|^mirrorlist|#mirrorlist|g \-e s|^#baseurlhttp://mirror.centos.org/centos|baseurlhttps://mirrors.tuna.tsinghua.edu.cn/centos|g \-i.bak \/etc/yum.repos.d/CentOS-*.repo详见 https://mirrors.tuna.tsinghua.edu.…

函数与方法有区别?

有区别&#xff0c;当然是有区别。 不管是java、rust还是go&#xff0c;他们都是不一样的。 先看定义&#xff1a; 函数&#xff08;Function&#xff09; 是一段独立的代码块&#xff0c;用于执行特定的任务。函数可以被多次调用&#xff0c;并且可以接受参数和返回结果。在G…

尼科彻斯定理

目录 1.题目概述 2.题解 思路分析 具体实现 1.题目概述 验证尼科彻斯定理&#xff0c;即&#xff1a;任何一个整数m的立方都可以写成m个连续奇数之和。 例如&#xff1a; 1^31 2^335 3^37911 4^313151719 输入一个正整数m&#xff08;m≤100&#xff09;&#xff0c;将…

pytorch 训练过程内存泄露/显存泄露debug记录:dataloader和dataset导致的泄露

背景 微调 mask-rcnn 代码&#xff0c;用的是 torchvision.models.detection.maskrcnn_resnet50_fpn 代码&#xff0c;根据该代码的注释&#xff0c;输入应该是&#xff1a; images, targetsNone (List[Tensor], Optional[List[Dict[str, Tensor]]]) -> Tuple[Dict[str, Te…