前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >mysql insert duplicate key update 死锁分析

mysql insert duplicate key update 死锁分析

作者头像
YG
发布2021-03-04 10:31:58
3.8K1
发布2021-03-04 10:31:58
举报
文章被收录于专栏:YG小书屋YG小书屋

背景

数据入库这块有离线和实时两套入库系统,写同一个db的同一批mysql表,两边用的都是insert into table on duplicate key update这种方式。实时一直运行,离线5分钟更新一次,当两套系统同时运行时出现了死锁问题,频率还挺高。事务的隔离级别是read committed 读提交。

原因分析&解决方案

这里面分两种情况,一种是带主键的insert duplicate key update,一种是没有主键带唯一索引的insert duplicate key update。

1、带主键的insert duplicate key update

实时入库的batch大小是1w,离线入库的batch大小也是1w,为了提高入库效率 ,两边都开启了事务。当两边同一批插入的数据中包含了相同的数据,且顺序不一致,此时会出现死锁。比如说实时任务当前插入的数据包含id为1,2的数据,离线任务当前插入的数据包含2,1。此时实时任务获取了id为1数据的锁,等2的数据锁,离线任务获取了id为2的数据锁,等id为1数据锁,产生了死锁。

这种情况比较简单,处理方式有两种:

1、减少batch大小,减少了同一批数据中包含相同数据的概率,也就减少了死锁发生的概率

2、入库前对sql按照id排序,即使出现相同数据,只要保证顺序相同就不会出现死锁

2、带唯一索引的insert duplicate key update

https://developer.aliyun.com/article/727076 这篇文章讲的很清楚,这里我大致聊一下。 insert相关的有四种锁。

  • record锁,也就是锁一条记录,这时其他事务读写不了当前加锁的记录。
  • gap锁,锁一个区间。比如说db中有1,3,5,那么对应的区间就有(-∞,1),(1,3),(3,5),(5,+∞),该锁可以锁住上面四个区间的任何一个或者多个。
  • next-key锁,锁一条记录和小于该记录最近的一个gap,本质上就是record锁加上gap锁。比如说db中有1,3,5,那么对应的区间就有(-∞,1],(1,3],(3,5],(5,+∞],该锁可以锁住上面四个区间的任何一个或者多个。
  • Insert Intention锁(插入意向锁):这个锁是在数据插入之前会加此锁。它是一种轻量的Gap锁,同时也是意向排他锁的一种。它的存在使得多个事务在写入不同数据到统一索引间隙的时候,不会发生锁等待。

插入唯一索引时判断索引是否存在。如果不存在,会在数据所属的gap添加Insert Intention锁。由于意向锁是轻量gap锁,这时即使有同gap的其他数据插入,两者之间不会互相影响。

如果插入的索引已经存在,会在索引值位置插入next-key锁。next-key锁包含record锁和gap锁,gap锁会锁一个范围,锁住期间,其他事务不能向该范围插入数据。如果此时两个事务各自获取到了一个next-key锁,此时都需要向对方获取到的next-key锁范围插入数据,就会出现死锁。

举例: code字段有唯一索引。初始数据:insert into test2 (code, other) values(1,1),(3,3),(5,5) 事务1: insert into test2(code,other)values(3,3) on duplicate key update other=values(other); 由于code为3的数据已经存在,所以会在(1,3]这个范围加next-key锁。 事务2: insert into test2(code,other)values(5,5) on duplicate key update other=values(other); 由于code为5的数据已经存在,所以会在(3,5]这个范围加next-key锁。 如果此时事务1插入一条code为4的数据,那么此时会等待事务2 (3,5]的next-key锁释放; 如果同时事务2插入一条code为2的数据,那么此时会等待事务1 (1,3]的next-key锁释放; 形成死锁。

解决方案: 1、减少batch的大小,单个事务获取到的next-key锁的范围就会变少,减少死锁的概率。 2、重试。 3、插入数据时添加主键。如果插入数据时带上主键,那么就不会产生next-key锁,会退化到第一种情况(带主键的insert duplicate key update)。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 原因分析&解决方案
    • 1、带主键的insert duplicate key update
      • 2、带唯一索引的insert duplicate key update
      相关产品与服务
      批量计算
      批量计算(BatchCompute,Batch)是为有大数据计算业务的企业、科研单位等提供高性价比且易用的计算服务。批量计算 Batch 可以根据用户提供的批处理规模,智能地管理作业和调动其所需的最佳资源。有了 Batch 的帮助,您可以将精力集中在如何分析和处理数据结果上。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档