日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

两个小工具,MySQL死锁分析,新技能又Get!!!

發(fā)布時間:2025/3/21 数据库 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 两个小工具,MySQL死锁分析,新技能又Get!!! 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

數(shù)據(jù)庫死鎖,是最難調(diào)試與追蹤的。

場景如下:

同一個表,事務(wù)內(nèi)先插入一條記錄,再更新這條記錄,并發(fā)時會死鎖。

并且能夠復現(xiàn)。

可以通過什么工具模擬并發(fā)事務(wù),查看信息,解決問題呢?這是今天要分享的內(nèi)容。

一、前置準備

set session transaction isolation level repeatable read; set session autocommit=0;create table t (id int(20) primary key AUTO_INCREMENT,cell varchar(20) unique )engine=innodb;start transaction; insert into t(cell) values(11111111111); insert into t(cell) values(22222222222); insert into t(cell) values(33333333333); commit;

說明:

(1)案發(fā)時,事務(wù)隔離級別RR;

(2)多終端實驗,需要關(guān)閉事務(wù)自動提交;

(3)建表,設(shè)置PK與unique,初始化數(shù)據(jù);

二、并發(fā)事務(wù)模擬

Session A: start transaction; insert into t(cell)values(44444444444); ?[1]Session B:start transaction;insert into t(cell) values(55555555555); [2] update t set cell=123 where cell=44444444444; [3]???update t set cell=456 where cell=55555555555; [4]

開啟兩個終端模擬并發(fā)事務(wù):

(1)紅色SQL為事務(wù)A;

(2)黑色SQL為事務(wù)B;

(3)[1][2][3][4]為執(zhí)行時序;

三、實驗現(xiàn)象

insert into t(cell)values(44444444444); ?[1]

事務(wù)A插入數(shù)據(jù),最先執(zhí)行

結(jié)果:插入成功

insert into t(cell) values(55555555555); [2]

事務(wù)B插入數(shù)據(jù),第二執(zhí)行

結(jié)果:插入成果

update t set cell=123 where cell=44444444444; [3]

事務(wù)A修改[1]中插入的數(shù)據(jù),第三執(zhí)行

結(jié)果:阻塞,等待執(zhí)行結(jié)果

畫外音:修改一條自己插入的數(shù)據(jù),在等待什么呢?

update t set cell=456 where cell=55555555555; [4]

事務(wù)B修改[2]中插入的數(shù)據(jù),最后執(zhí)行

結(jié)果:

(1)事務(wù)B死鎖,事務(wù)B被回滾;

(2)事務(wù)A中,[3]語句阻塞結(jié)束,執(zhí)行成功;

畫外音:說明事務(wù)A中阻塞的語句,確實在等事務(wù)B中的某個鎖。

四、結(jié)果分析

兩個事務(wù),各自修改自己插入的數(shù)據(jù),卻產(chǎn)生了死鎖,確實詭異。

上述實驗現(xiàn)象的兩個核心問題是:

(1)語句[3]阻塞,在等待什么鎖?

(2)語句[4]死鎖,此時事務(wù)A和事務(wù)B一定是彼此占住一把鎖,請求彼此的鎖,這些鎖又是什么呢?

工具一:

show engine innodb status;

畫外音:前文《超贊,InnoDB調(diào)試死鎖的方法!》就詳細分享過,InnoDB死鎖的分析實踐。

執(zhí)行之后,顯示的內(nèi)容如下(放大仔細看):

信息很多,別急,樓主娓娓道來。

第一部分,關(guān)鍵詞是:

(1)Transaction 1,事務(wù)3998;

(2)在執(zhí)行

update t set cell=123 where cell=44444444444;

(3)正在等待鎖釋放(waiting for this lock to be granted),記錄鎖(record locks),主鍵索引上(index primary),互斥鎖(lock_mode X),物理記錄(physical record),asc 55555555555;

畫外音:英文比較差沒事,抓關(guān)鍵詞。

畫外音,InnoDB存儲引擎,聚集索引與非聚集索引的實現(xiàn)方式,決定了鎖會加在聚集索引上,詳見文章:

《1分鐘了解MyISAM與InnoDB的索引差異》。

第二部分,關(guān)鍵詞是:

(1)Transaction 2,事務(wù)3999;

(2)正在執(zhí)行

update t set cell=456 where cell=55555555555;

(3)持有鎖(holds the lock),記錄鎖(record locks),主鍵索引上(index primary),互斥鎖(lock_mode X),物理記錄(physical record),asc 55555555555;

(4)正在等待鎖釋放(waiting for this lock to be granted),記錄鎖(record locks),主鍵索引上(index primary),互斥鎖(lock_mode X),物理記錄(physical record),asc 11111111111;

(5)事務(wù)2回滾(we roll back transaction 2);

通過show engine innodb status; 能夠看到很多事務(wù)與鎖之間的信息,對分析問題十分有幫助,這些信息,能夠解釋一些問題,但仍有兩個疑惑:

(1)事務(wù)1為啥想拿55555555555的鎖?

畫外音:這正是,事務(wù)1被阻塞的原因。

(2)事務(wù)2為啥想拿11111111111的鎖?死鎖的發(fā)生,說明事務(wù)1此時真占著11111111111的鎖,這又是為什么呢?

畫外音:第一個事務(wù)占111搶555,第二個事務(wù)占555搶111,循環(huán)嵌套,才會死鎖。

工具二:

explain

為了進一步尋找原因,可以通過explain看下導致死鎖語句的執(zhí)行計劃。

explain update t set cell=456 where cell=55555555555;

select_type:SIMPLE

這是一個簡單類型的SQL語句,不含子查詢或者UNION。

type:index

訪問類型,即找到所需數(shù)據(jù)使用的遍歷方式,潛在的方式有:

(1)ALL(Full Table Scan):全表掃描;

(2)index:走索引的全表掃描;

(3)range:命中where子句的范圍索引掃描;

(4)ref/eq_ref:非唯一索引/唯一索引單值掃描;

(5)const/system:常量掃描;

(6)NULL:不用訪問表;

上述掃描方式,ALL最慢,逐步變快,NULL最快。

懷疑點1:明明cell字段有uniq索引,為何要進行走PK索引的全表掃描呢?

possible_keys:NULL

可能在哪個索引找到記錄。

key:PRIMARY

實際使用索引。

畫外音:使用PK進行的全表掃描。

ref:NULL

哪些列,或者常量用于查找索引上的值。

懷疑點2:where條件中的查詢條件55555555555,本來應(yīng)該作為在索引上被檢索的值呀?

rows:5

找到所需記錄,預估需要讀取的行數(shù)。

懷疑點3:明明修改的是5,為何初始化的1,2,3,以及第一個事務(wù)插入的4,以及第二個事務(wù)插入的5,都要被讀取呢?不應(yīng)該全表掃描呀。

通過explain,基本已經(jīng)可以判斷:

update t set cell=456 where cell=55555555555;

并沒有和我們預想一樣,走cell索引進行查詢,而是走了PK索引進行了全表掃描

再仔細一看:

建表的時候cell定義的是字符串類型。

create table t (id int(20) primary key AUTO_INCREMENT,cell varchar(20) unique )engine=innodb;

更新的時候,

update t set cell=456 where cell=55555555555;

使用的是整數(shù)類型。

類型轉(zhuǎn)換,會導致全表掃描,出現(xiàn)鎖升級,鎖住全部記錄。

加上引號,再次通過explain驗證一下:

explain update t set cell= '456 ' where cell= '55555555555 ';

果然印證了猜想:

(1)type:range,變?yōu)榱俗咚饕淖址葘?#xff0c;范圍掃描;

(2)possible_keys:cell,通過cell索引找到了記錄;

(3)key:cell,實際使用cell索引;

(4)ref:const,使用了常量' 555'進行比對;

(5)rows:1,預估讀取行數(shù)是1;

這下全部可以解釋了。

總結(jié)

就本例而言:需要注意字符串與整數(shù)之間的強制類型轉(zhuǎn)換,有時候少一個引號,就會使得行鎖升級為表鎖。

死鎖是MySQL中非常難調(diào)試的問題,常見的思路與方法有:

(1)通過多終端模擬并發(fā)事務(wù),復現(xiàn)死鎖;

(2)通過show engine innodb status;?可以查看事務(wù)與鎖的信息;

(3)通過explain可以查看執(zhí)行計劃;

思路比結(jié)論更重要,希望大家有收獲。

總結(jié)

以上是生活随笔為你收集整理的两个小工具,MySQL死锁分析,新技能又Get!!!的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。