mysql复合索引造成的死锁

问题出现

公司的数据库经常出现死锁, 造成服务不稳定,搭载数据库的机器还经常OOM, 到时候只能重启数据库
查询show engine innodb status\G查看死锁信息

t1.png
t2.png

可以看到是两条update语句产生了死锁, 其蹊跷之处在于其中第一条只操作了一张表, 另外一条操作了两张表, 乍一看看不出原因, 可以知道的结论是第一条语句锁住了8行, 第二条语句锁住了851243, 但是他们都在等待对方锁住的记录。 查看了一下调用, 其中第二条语句是一个定时任务, 每隔五分钟会执行一次, 第一条语句是随用户点击而执行的, 现在的死锁频率为每天一次, 看上去死锁发生率已经很高了。那我们首先可以来分析一下SQL语句。

SQL语句分析

首先GlobalDiscountCode这张表数据库的隔离级别:REPEATABLE-READ, 索引有

5.png

看一下这条语句的查询结果


QQ截图20170615193050.png

可以看到有13条, 这条UPDATE语句在主键索引上本应该有13条X锁的, 所以可以肯定的是至少有一条主键索引被第二个SQL语句给锁住了

explain一下这条语句看一看

6.png

可以发现它走的索引是userId_code这条复合索引。 那么加锁顺序也是按照这条复合索引来的。所以我们可以得知在userId_code这个索引上加的是gap锁+X锁, 在主键索引上加的是X锁, 通过开始的死锁信息可以看出, 发生死锁的地方是X锁, 所以是在主键索引处。

那我们分析一下第二个SQL语句。 这条语句看起来比较复杂, 会inner join两个表的update


3.png

我们通过改写成select语句来explain一下, 看出对GlobalDiscountCode这张表实际上是走的遍历了全表, 所以理论上来说它要将这张表逐行锁住, 同时也要锁住GlobaOrder这张表中选中的记录, 加锁顺序按照GlobalDiscountCode的主键顺序来的

死锁分析

死锁的成因都是因为加锁顺序的问题, 比较常见的是显示死锁, 也就是两个事物对两把锁上锁顺序不同产生的, 不常见的是两条语句因为采用的索引不同, 导致的加锁顺序不同, 按照何登成的博客上画的可以看出原因

4.png

显然我们这里的死锁成因肯定也是因为用索引导致的加锁顺序不一致, 那么看一看两条语句的加锁顺序吧, 我们参照之前第一条语句的select结果可以知道, 它走的是userId_code这条复合索引, 然后用这条复合索引的时候id是乱序的, 所以对主键索引的加锁也是不按照id顺序来的, 但是第二条语句对主键索引的加锁顺序是按照id顺序的, 所以这两天语句就会产生死锁。

死锁解决

mysql版本为5.5.11时候, 默认会使用复合索引, 而不走单独的索引, 如果是走userId这个索引的话, 对主键索引的加锁就也顺序了, 那么我们需要显示使用userId这个索引就可以解决问题了, 所以更改第一条SQL语句为
update GlobalDiscountCode FORCE INDEX(userId) set readed=1 where userId=? 这样就不会产生死锁了。
找到原因是因为数据库选择了复合索引才导致的死锁, 看来复合索引不能乱加。 会导致加锁顺序乱掉的。

后记

最开始运维和DBA都在纠结于修改第二条SQL语句, 认为那条语句写的不够好, 执行了太长时间, 导致的死锁, 说那条语句里用了效率不高的in, 所以应该把in去掉, 换成六条单独的语句, 但是实际上试了下并没有提高效率, 执行差不多还是一秒钟。 同时第二条SQL语句执行频率很低, 五分钟执行一次, 但是已经造成每天都会有死锁了, 说明死锁出现的几率已经很高了, 即便通过提高效率缩短执行时间, 提高了一两倍也没什么意义。
DBA还想办法缩小锁范围。 但是这个语句实际上是没法拆分的, 如果拆分成两条去写, 也就是先select出来再update, 但是这样就丧失了隔离性, 所以也是不可取的。当然如果按照业务来讲还是有缩小的可能性, 比如说我们可以按照日期排序, 只update最近一周的订单, 这样就会把锁范围缩小很多, 出现死锁的可能性也基本没有了, 因为我们发优惠券的频次一般会大于一周, 这也是解决死锁的一种思路。
考虑到肯定是这两条语句之间的交叉死锁, 而且第二条语句其实相当于表锁, 但是是逐行执行的这一特点(InnoDB不会锁升级)于是我打算暴力一些, 直接把GlobalDiscountCode这个表表锁,写法如下

7.png

这么执行, 效率也是提升了的, 而且理论上也不会产生死锁了, 不过显示锁表担心会出问题, 没敢上线。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容