| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 大数据 -> 记录一次mysql死锁 -> 正文阅读 |
|
[大数据]记录一次mysql死锁 |
一,死锁发现 项目中有一个接口包含更新操作1,后面发现更新失败,通过查看应用程序日志,发现发生了死锁 sql 1 如下 1.最初版本根据id为条件,更新(plan_start_time 二级索引) update tt_task ?SET org_id = ?, ? org_name = ?, ? ?plan_start_time = ? ? ? ? ? ?where id = ? 2.第二版根据order_number唯一索引为条件,更新(这样改当时想法是减少对id的争夺,后面发布后未生效,似乎导致了更严重的死锁(更新1后面还有一个更新2操作,从应用日志中发现更新2的死锁)) update tt_task ?SET org_id = ?, ? org_name = ?, ? ?plan_start_time = ? ? ? ? ? ?where order_number = ? 二,死锁日志 1.最初根据id更新死锁,更新1 ?2.改成根据唯一索引order_number更新 ?3.更新2死锁(更新1后面的一个更新操作)(plan_arrive_time 二级索引) update tt_task ? ? ? ? ?SET navigation_distance = ?,? ? plan_arrive_time = ? ? ? ? ? ?where id = ? ?4.死锁日志分析 上面上传的死锁日志是不全的,出现死锁日志有的不是一处错误,有的是连续两个,甚至是三个死锁报错 4.1 连续两个报错日志,且是不同的两条数据,发生报错时间s秒级 4.2 只有一个报错日志,某一条数据发生死锁 4.3 连续出现3处死锁日志,如上图3,1.3处是更新2的死锁,2处是更新1的死锁,且分别是3条不同的数据 三,猜想 一般死锁原因:并发+两个事物+操作同一条数据(具体原因:待补充) 比较疑惑的是 1.更新操作,条件已经是id,最大限度的减少了死锁,为什么还会发生 2.只有一条死锁报错,只涉及到一条数据,怎么产生死锁的(不会并发啊) 3.连续两个死锁日志,是两个不同的数据(不是争夺同一个数据引发死锁吗) 猜想1: 肯定有并发操作 针对发生死锁的这个表,项目中有很多更新操作(确实有,哪些比较模糊) 当前发生死锁的更新,肯定是和哪个更新操作发生了冲突,两个不同事物各自持有锁 方案 1,怎么优化当前发生死锁的sql,但是已经是根据id更新的,死锁概率应该比较低啊,方向是这里,所以有了改成根据唯一索引更新,想减少对主键id的占用。 具体操作 1.1 把代码逻辑中更新报错的sql,单独写一个根据唯一索引更新,独立与其他更新操作 1.2 把更新操作上的,@Transation 事物注解去掉,如下图? 结果:但是上线后,未生效 四,继续排查 因为第一次改动未生效,发下可以查询mysql日志,如下 1.查询mysql死锁日志 SHOW ENGINE INNODB STATUS; 2.mysql日志详情 更新2的死锁日志
之前未发现的死锁日志 (grabbing_status 二级索引),当作更新3 update tt_task
3. 再结合业务日志发现以下问题 3.1.实际上更新2(包含在更新1中,且是异步的)的死锁概率大于更新1 3.2.更新1,更新2,这两个受害者,都与自己无关,也与对方无关,还有一个第三者,是第三者导致了更新1,更新2,甚至更多地方的死锁 至此,发现了导致死锁的根本sql 4.可归类为 更新1(死锁受害者) 更新2(死锁受害者) 更新3(死锁引发者) 五,死锁知识 归纳如下 【1】基本概念 【2】锁知识 1.mysql的事务支持与存储引擎有关,MyISAM不支持事务,INNODB支持事务,更新时采用的是行级锁 2.行级锁必须建立在索引的基础 3.行级锁并不是直接锁记录,而是锁索引,如果一条SQL语句用到了主键索引,mysql会锁住主键索引;如果一条语句操作了非主键索引,mysql会先锁住非主键索引,再锁定主键索引。 4.在并发高的应用中,批量更新一定要带上记录的主键,优先获取主键上锁,这样开业减少死锁的发生 5.在采用INNODB的MySQL中,更新操作默认会加行级锁,行级锁是基于索引的,在分析死锁之前需要查询一下mysql的执行计划,看看是否用到了索引,用到了哪个索引,对于没有用索引的操作会采用表级锁。如果操作用到了主键索引会先在主键索引上加锁,然后在其他索引上加锁,否则加锁顺序相反。在并发度高的应用中,批量更新一定要带上记录的主键,优先获取主键上的锁,这样可以减少死锁的发生。 6.?innodb 读不加锁。但是写加了锁,在什么时候加锁呢? 在我们执行一条 update 语句的时候。 在什么时候释放锁呢? 在事务提交的时候。 上面说过 锁会在事务提交的时候释放,所以 两个事务就锁死了。 7.where条件 与表锁/行锁 在 update 语句的 where 条件没有使用索引,就会全表扫描; where条件里面,不加索引时,update会使用“表锁”进行更新,影响所有行的查询更新; 加了索引后,使用“行锁”进行udpate,只锁当前行。不影响其他行的查询更新。 mysql的行锁是通过索引加载的,即是行锁是加在索引响应的行上的,要是对应的SQL语句没有走索引,则会全表扫描 【3】死锁必要条件 1.产生死锁的必要条件 多个并发事务(2个或者以上) 每个事物都持有了锁(或者是已经在等待锁) 每个事务都需要再继续持有锁(为了完成事务逻辑,还必须更新更多的行) 事物之间产生加锁的循环等待,形成死锁 2.产生死锁的必要条件 【4】加锁流程 4.1 对同一条数据,T1通过二级索引更新,T2通过聚簇索引更新T1作为更新条件二级索引,如果T1先拿到二级索引,T2先拿到聚簇索引。此时就会出现T1等T2的聚簇索引,T2等T1的二级索引的死锁 事物1: 根据二级索引作为条件,更新二级索引;先锁二级索引(相关记录),再锁主键索引(相关记录) 事物2: 根据主键更新数据,更新的字段中包含;先锁主键索引(相关记录),再锁二级索引(相关记录) 形成了(针对单个的一条记录(很多这样记录)) 事物1锁定二级索引记录,持有二级索引锁,待获取主键索引锁 事物2锁定主键索引记录,持有主键索引锁,待获取二级索引锁 六,死锁原因,深度分析 七,方案 针对更新3,引发死锁的sql 更新条件为二级索引的sql进行优化,改为先查询id,再根据id更新 mysql死锁的例子_MySQL数据库的一次死锁实例分析_C18298182575的博客-CSDN博客 MySQL造成更新死锁及插入死锁的几种常见原因_yue_hu的博客-CSDN博客_mysql update 死锁 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/23 16:50:19- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |