mysql-不恰当的update语句使用主键和索引导致mysql死锁
背景知识:
MySQL有三种锁的级别:页级、表级、行级。
MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking);BDB存储引擎采用的是页面锁(page-level locking),但也支持表级锁;InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。
MySQL这3种锁的特性可大致归纳如下:
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
行级锁并不是直接锁记录,而是锁索引,如果一条SQL语句用到了主键索引,mysql会锁住主键索引;如果一条语句操作了非主键索引,mysql会先锁住非主键索引,再锁定主键索引。
问题现象:
线上出现错误日志:mysql死锁问题。
排查过程:
请DBA协助查看mysql错误日志,发现确实存在死锁问题。
发生死锁的就是以上两条sql,两次请求时间仅间隔1毫秒。
涉及到的数据库表如下:
根据背景知识里的红色描述:如果用到了主键索引,mysql会锁定主键索引,如果用到了非主键索引,msyql会先锁定非主键索引,再锁定主键索引。因此,在SQL(1)中先锁定了next_consume_time这个非主键索引,还需要锁定主键索引,此时SQL(2)直接锁定了主键索引,而其update语句中set使用了next_consume_time,同时还需要next_consume_time这个非主键索引。因此两条SQL就出现了对索引资源的竞争,造成死锁。
从业务方面考虑:两条SQL是从两台机器发起的请求,而这两条SQL在业务上是存在了先后顺序的,先执行SQL(1)占用需要执行的表记录,在执行SQL(2)进行业务操作。从日志中发现,54机器执行的是SQL(2),那么54机器肯定已经执行过了SQL(1),此时该条记录已经是被占用状态了,55机器又怎么会执行SQL(2)呢?难道是没被占用吗?
DBA又查看mysql的binlog,发现queue_id为283410的记录,确实正常执行过SQL(1),那55机器为什么还要再次执行SQL(1)呢?
又查看开放平台日志,54机器线程启动时间为:
2016-09-25 11:12:40,463] [dbMsgConsumer-3] [INFO] [taskLogger] [////] - [QueueConsumeTask started]
55机器线程启动时间为:
2016-09-25 11:12:40,583] [dbMsgConsumer-2] [INFO] [taskLogger] [////] - [QueueConsumeTask started]
两者仅相差120毫秒。
目前咱们mysql默认的事务隔离级别是REPETABLE READ(可重复读),即在同一个事务内,多次查询结果是一致的。
当54机器开启事务,执行SQL(1)时,事务还未提交,55机器也执行SQL(1),此时55机器查询到的记录是更新前的,54机器提交事务,再去执行SQL(2),此时由于SQL(1)是范围查询,SQL(2)是主键查询,SQL(2)的执行时间要远远少于SQL(1),会造成54机器执行SQL(2)时,55机器还未执行完成SQL(1),造成两条机器互相抢占资源,造成死锁。54和55两台机器执行示意图如下:
解决办法:
修改SQL(1)为两步操作,首先通过条件查询出符合条件的记录,然后根据查询出的结果的主键id再进行update操作。
修改后sql,先执行查询操作:
再执行修改操作,使用获取到的主键ID
代码修改如下:
经验教训:
电商无论前台后台的程序,都不应该存在仅根据非主键的几个字段一查就要update/delete的场景。即使有,也应该改为先把要更新的记录查出来然后逐条按主键id更新。
原文blog:http://blog.csdn.net/lzy_lizhiyang/article/details/52678446
mysql-不恰当的update语句使用主键和索引导致mysql死锁的更多相关文章
- 不恰当的update语句使用主键和索引导致mysql死锁
背景知识: 截至目前,MySQL一共向用户提供了包括DBD.HEAP.ISAM.MERGE.MyIAS.InnoDB以及Gemeni这7种Mysql表类型.其中DBD.InnoDB属于事务安全类表,而 ...
- 【转载】mysql主键的缺少导致备库hang
最近线上频繁的出现slave延时的情况,经排查发现为用户在删除数据的时候,由于表主键的主键的缺少,同时删除条件没有索引,或或者删除的条件过滤性极差,导致slave出现hang住,严重的影响了生产环境的 ...
- mysql主键的缺少导致备库hang
最近线上频繁的出现slave延时的情况,经排查发现为用户在删除数据的时候,由于表主键的主键的缺少,同时删除条件没有索引,或或者删除的条件过滤性极差,导致slave出现hang住,严重的影响了生产环境的 ...
- Mybatis笔记 – insert语句中主键的返回
在DBMS中可以使用insert语句显示指定自增主键值,但Mybatis中不可,即使指定了也无效,可以使用特殊的方式返回主键. 一.自增主键返回 mysql自增主键执行insert提交 ...
- mysql 插入数据失败防止自增长主键增长的方法
mysql设置了自增长主键ID,插入失败的那个自增长ID也加一的,比如失败5个,下一个成功的不是在原来最后成功数据加1,而是直接变成加6了,失败次数一次就自动增长1了,能不能让失败的不增长的? 或者说 ...
- SQL语句新建表,同时添加主键、索引、约束
SQL语句新建数据表 主键,索引,约束 CREATE TABLE [dbo].[T_SendInsideMessageRec]( [SendInsideMID] [uniqueidentifier ...
- MySQL主键和索引的联系及区别
转载自:http://www.nowamagic.net/librarys/veda/detail/1954 关系数据库依赖于主键,它是数据库物理模式的基石.主键在物理层面上只有两个用途: 惟一地标识 ...
- MySQL主键与索引的区别和联系
MySQL主键与索引的区别和联系 关系数据库依赖于主键,它是数据库物理模式的基石.主键在物理层面上只有两个用途: 惟一地标识一行. 作为一个可以被外键有效引用的对象. 索引是一种特殊的文件(Inn ...
- mysql,主键与索引的区别和联系
关系数据库依赖于主键,它是数据库物理模式的基石.主键在物理层面上只有两个用途: 惟一地标识一行. 作为一个可以被外键有效引用的对象. 索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成 ...
随机推荐
- Java使用Zxing生成、解析二维码工具类
Zxing是Google提供的关于条码(一维码.二维码)的解析工具,提供了二维码的生成与解析的方法. 1.二维码的生成 (1).将Zxing-core.jar 包加入到classpath下. (2). ...
- hibernate丢失更新
如果多个线程操作基于同一个查询结构对表中的记录进行修改,那么后修改的记录将会覆盖前面修改的记录,前面的修改就丢失掉了,这就叫做更新丢失.Serializable可以防止更新丢失问题的发生.其他的三个隔 ...
- 系统整理 精讲 swift 泛型
泛型是一种非常领会的语法,让我很是膜拜! 真是让人又爱又恨,学不懂的时候很抓狂 允许程序在函数,枚举,结构体,类中定义类型形参(类型可以动态改变) 每次使用可以传入不同类型的形参! Array< ...
- c++ STL deque容器成员函数
deque是双向队列,即可以在头部插入删除,也可以在尾部插入删除.内部并不连续,这一点和vector并不一样.可能第1个元素和第2个元素的地址是不连在一起的.在使用时用it迭代器会安全一点. 这是c+ ...
- Python爬虫实战:爬糗事百科的段子
一个偶然的机会接触了Python,感觉很好用,但是一直在看c++啥的,也没系统学习.用过之后也荒废了许久.之前想建个公众号自动爬糗事百科的段子,但是没能建起来,真是尴尬,代码上传的服务器上之后,不能正 ...
- POJ 3126 Prime Path(筛法,双向搜索)
题意:一个4位的素数每次变动一个数位,中间过程也要上素数,问变成另一个的最小步数. 线性筛一遍以后bfs就好.我写的双向,其实没有必要. #include<cstdio> #include ...
- 【POJ2774】Long Long Message(后缀数组求Height数组)
点此看题面 大致题意: 求两个字符串中最长公共子串的长度. 关于后缀数组 关于\(Height\)数组的概念以及如何用后缀数组求\(Height\)数组详见这篇博客:后缀数组入门(二)--Height ...
- FreeRTOS_软件定时器
FreeRTOS 软件定时器 实验 创建2个任务,start_task.timercontrol_task. start_stask:创建timercontrol_task任务:创建周期定时器Auto ...
- 2017.12.6 计算机算法分析与设计---------Fibonacci数列
(1)题目: 无穷数列1,1,2,3,5,8,13,21,34,55,--,称为Fibonacci数列.它可以递归地定义为: 第n个Fibonacci数可递归地计算如下: int fibonacci( ...
- x5webview 微信H5支付
mWebView.setWebViewClient(new WebViewClient() { // @Override // public boolean shouldOverrideUrlLoad ...