`

mysql 2个sql更新不同记录但死锁

 
阅读更多

问题起因:

两条写sql,操作的记录没有任何冲突,但发生死锁

 

预备知识:

InnoDB行锁是通过给索引上的索引项加锁来实现的

 

创建测试表

CREATE TABLE `t1` (

  `pk_id` INT(11) NOT NULL,

  `type` INT(11) NOT NULL,

  `status` INT(11) NOT NULL,

  PRIMARY KEY (`pk_id`)

);

create index idx_type on t1(type);

create index idx_status on t1(status);

生成测试数据

INSERT INTO  t1 (pk_id,TYPE,STATUS)

VALUES

(1,1,0),

(2,1,0),

(3,1,0),

(4,2,0),

(5,2,0),

(6,1,1),

(7,1,1),

(8,2,1);

 

例1.不一样的锁等待

连接A执行

SET autocommit=0;

BEGIN;

SELECT * FROM t1 force index(PRIMARY) WHERE pk_id<4 AND TYPE=1 AND pk_id!=2 FOR UPDATE;

马上返回查到的结果有两条pk_id为1和3

 

连接B执行

SET autocommit=0;

BEGIN;

SELECT * FROM t1 WHERE pk_id=2 FOR UPDATE;

执行后连接B一直是等待状态,如果连接A commit,连接B马上就执行完成

说明:连接A虽然查出来的结果只有pk_id为1和3的两条记录,但把pk_id为2的PRIMARY索引记录也锁住了,所以连接B一直等待

 

换个索引试试

在连接A里

commit;

SELECT * FROM t1 force index(idx_type) WHERE pk_id<4 AND TYPE=1 AND pk_id!=2 FOR UPDATE;

注意只换了force index使用的索引,其他都没变

在连接B里想写操作TYPE=1的记录(pk_id为1、2、3、6、7)都等待,因为连接A把idx_type中TYPE=1的记录都锁了

和之前例子对照可以发现,索引锁是按使用的索引来操作,并且可以确定的是锁的范围会超出查询结果范围,这点和一般以为的不一样,具体算法还有待研究。

 

2.死锁

连接A执行

COMMIT;
SET autocommit=0;
SELECT * FROM t1 WHERE pk_id<5 FOR UPDATE;

连接A先锁住了pk索引的部分记录

 

接着连接B执行

COMMIT;
SET autocommit=0;

SELECT * FROM t1 FORCE INDEX (idx_status) WHERE STATUS=0 FOR UPDATE;

连接B锁往了idx_status的部分记录,再要锁pk时被连接A block,所以只能等待

 

最后连接A执行

UPDATE t1 SET STATUS=6 WHERE pk_id<5;

这时连接B报dead lock found

简单来讲连接A先锁住pk,B先锁住idx_status再拿pk就拿不到,这时A再拿idx_status就死锁了

类似于一个人有X但要Y,一个人有Y但要X,互不相让,就死锁了。

 

3.想不到的死锁

把例1和例2的情况结合起来,就会出来本文最开始碰到的问题,想不到的死锁,即更新的记录完全不冲突,但就是死锁了

比如

SELECT * FROM t1 force index(idx_type) WHERE pk_id<4 AND TYPE=1 FOR UPDATE;

update t1 set status=1 where pk_id=6

虽然想操作的记录不同,但锁的记录有相同的,所以也可能会死锁

 

例4.index merge死锁

如果sql where里同时使用了type和status,因为type和status上都有单字段索引,所以explain会发现使用了index merge

有的sql使用的索引是先idx_type再idx_status,有的先idx_status再idx_type

这样如果锁的记录有冲突,就可能和例3一样死锁了

 

解决方案:

1.只有一个pk,不要其他索引。这样只有lock wait,不会死锁

2.有多个index,但写数据时使用的都是同样的index组合

3.有多个index,按不同的index组合写数据,但逻辑上保证锁的记录不冲突

 

时间所限,只整理了大概的逻辑,一些细节未深入。有兴趣的可以看看mysql的next-key locking

0
2
分享到:
评论

相关推荐

    该如何解决MySQL中的死锁问题.txt

    MySQL中的死锁是指两个或多个事务在相互等待对方释放资源,导致它们都无法继续执行的情况。解决MySQL中的死锁问题通常涉及多个方面,包括监控死锁、分析死锁原因、优化事务设计以及调整系统配置等。以下是一些解决...

    SQL2008中SQL应用之- 死锁(Deadlocking)

    所以,SQL Server会选择死锁中的一个会话作为“死锁牺牲品”。 注意:死锁牺牲品的会话会被杀死,事务会被回滚。 注意:死锁与正常的阻塞是两个经常被混淆的概念。 发生死锁的一些原因: 1、应用程序以不同的次序...

    收集一些常见的 MySQL 死锁案例

    这个项目收集了一些常见的 MySQL 死锁案例,大多数案例都来源于网络,并对其进行分类汇总,试图通过死锁日志分析出每种死锁的原因,还原出死锁现场。 实际上,我们在定位死锁问题时,不仅应该对死锁日志进行分析,...

    查看数据库死锁SQL

    该脚本为MYSQL数据库中查看死锁的语句,可以查看到死锁的ID,造成死锁的语句以及造成死锁的计算机

    Mysql查看死锁与解除死锁的深入讲解

    前段时间遇到了一个Mysql 死锁相关的问题,整理一下。 问题描述:Mysql 的修改语句似乎都没有生效,同时使用Mysql GUI 工具编辑字段的值时会弹出异常。 什么是死锁 在解决Mysql 死锁的问题之前,还是先来了解一下...

    详解SQL死锁检测的方法

    死锁(deadlock)指进程之间互相永久阻塞的状态,SQL可以检测到死锁,并选择终止其中一个事务以干预sql server死锁状态。 第一步:首先创建两个测试表,表goods_sort和goods 表goods_sort:创建并写入测试数据 IF ...

    查找MySQL中查询慢的SQL语句方法

    这可能是困然很多人的一个问题,MySQL通过慢查询日志定位那些执行效率较低的SQL 语句,用–log-slow-queries[=file_name]选项启动时,mysqld 会写一个包含所有执行时间超过long_query_time 秒的SQL语句的日志文件,...

    数据库死锁

    数据库死锁sql语句

    Mysql 数据库死锁过程分析(select for update)

    最近有项目需求,需要保证多台机器不拿到相同的数据,后来发现... for update经常导致数据库死锁问题,下面小编给大家介绍mysql 数据库死锁过程分析(select for update),对mysql数据库死锁问题感兴趣的朋友一起学习吧

    Mysql使用kill命令解决死锁问题(杀死某条正在执行的sql语句)

    主要介绍了Mysql使用kill命令解决死锁问题(杀死某条正在执行的sql语句)的相关资料,需要的朋友可以参考下

    新版 MySQL DBA 高级视频 基于MySQL 5.7 MySQL 8.0版本.rar

    │ 第二十一课MySQL常见错误-converted.pdf │ 第二十课MySQL索引和调优.pdf │ 第二课MySQL入门介绍.pdf │ 第五课MySQL常用函数介绍.pdf │ 第八课InnoDB内核.pdf │ 第六课SQL高级应用.pdf │ 第十一课MySQL表...

    由不同的索引更新解决MySQL死锁套路

    前几篇文章介绍了用源码的方式来调试锁相关的信息,这里同样用这个工具来解决一个线上实际的死锁案例,也是我们介绍的第一个两条 SQL 就造成死锁的情况。因为线上的表结构比较复杂,做了一些简化以后如下 CREATE ...

    一次mysql死锁的排查过程

     以前接触到的数据库死锁,都是批量更新时加锁顺序不一致而导致的死锁,但是上周却遇到了一个很难理解的死锁。借着这个机会又重新学习了一下mysql的死锁知识以及常见的死锁场景。在多方调研以及和同事们的讨论下...

    MySQL死锁的产生原因以及解决方案

    在实际应用中经常会遇到的与锁相关的异常情况,当两个事务需要一组有冲突的锁,而不能将事务继续下去的话,就会出现死锁,严 重影响应用的正常执行。 在数据库中有两种基本的锁类型:排它锁(Exclusive Locks,即X锁...

    MySQL中的死锁情况以及对死锁的处理方法

    死锁发生在事务试图以不同的顺序锁定资源。以StockPrice表上的两个事务为例:  事务1 START TRANSACTION; update StockPrice SET close = 45.50 WHERE stock_id = 4 and date = '2002-05-01'; UPDATE StockPrice ...

    MySQL Innodb表导致死锁日志情况分析与归纳

    案例描述在定时脚本运行过程中,发现当备份表格的sql语句与删除该表部分数据的sql语句同时运行时,mysql会检测出死锁,并打印出日志。两个sql语句如下:(1)insert into backup_table select * from source_table...

    MySQL死锁、锁、索引相关资料整理

    MySQL更新使用二级索引字段导致死锁问题分析,https://blog.csdn.net/a82514921/article/details/104616763 1. MySQL文档说明 1.1 InnoDB死锁 https://dev.mysql.com/doc/refman/5.6/en/innodb-deadlocks.html ...

    MySQL死锁问题分析及解决方法实例详解

    MySQL死锁问题是很多程序员在项目开发中常遇到的问题,现就MySQL死锁及解决方法详解如下: 1、MySQL常用存储引擎的锁机制 MyISAM和MEMORY采用表级锁(table-level locking) BDB采用页面锁(page-level locking)或表级...

    关于MySQL死锁问题的深入分析

    其实如果大家认真研读了我们之前写的3篇关于MySQL中语句加锁分析的文章,加上本篇关于死锁日志的分析,那么解决死锁问题应该也不是那么摸不着头脑的事情了。 准备工作 为了故事的顺利发展,我们需要建一个表: ...

    一次MYSQL死锁分析案例1

    背景pop购药上线后解冻操作经常发生死锁,报错日志如下:死锁sql语句select id from order_pay_statusupdate order_p

Global site tag (gtag.js) - Google Analytics