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数据表上的索引是表空间的一个组成 ...
随机推荐
- 解决WinSCP连接虚拟机
其实虚拟机你也可以将它形象化,认为它就是一台电脑,只是这个电脑在你的内存中,所以,一般电脑所具有的的功能虚拟机一样拥有,它也可以当成一台独立的个体哦. 针对很多使用WinSCP连接不上虚拟机的问题,这 ...
- spring的工厂方法
http://blog.csdn.net/nvd11/article/details/51542360
- hibernate课程 初探单表映射3-1 hibernate单表操作简介
本章简介: 1 单一主键 2 基本类型 3 对象类型 4 组件属性 5 单表操作CRUD实例
- git 使用流程 命令
克隆远程分支到本地 git clone <https://github.com/cqzyl/methods.js.git> 进入master分支 git checkout master 以 ...
- 学习笔记:location.hash和history.pushState()
在浏览器中改变地址栏url,将会触发页面资源的重新加载,这使得我们可以在不同的页面间进行跳转,得以浏览不同的内容.但随着单页应用的增多,越来越多的网站采用ajax来加载资源.因为异步加载的特性,地址栏 ...
- HDU1664 BFS + 数论 + 剪枝
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1664 , 一道比较蛋疼的搜索题. 这道题有很多坑点,一点处理不好就要TLE. 题意很简单,就是找到一个 ...
- Android(java)学习笔记86:Android提供打开各种文件的API接口:setDataAndType
1. Android 打开各种文件(setDataAndType) private void openFile(File file){ Intent intent = new Intent(); in ...
- 让你不再害怕指针——C指针详解(经典,非常详细)
http://blog.csdn.net/soonfly/article/details/51131141 前言:复杂类型说明 要了解指针,多多少少会出现一些比较复杂的类型,所以我先介绍一下如何完全理 ...
- Wired Memory
https://developer.apple.com/library/content/documentation/Performance/Conceptual/ManagingMemory/Arti ...
- 【BZOJ4196】[NOI2015] 软件包管理器(树链剖分)
点此看题面 大致题意: 有\(n\)个软件包,它们的依赖关系形成一棵树.现在,问你安装或卸载一个软件包,会影响多少个软件包的安装状态. 树链剖分 这道题应该是 树链剖分 算法比较入门的题目吧. 对于安 ...