如何找出MySQL中正在锁表的语句?
MySQL在每个版本发布时,都会加上一些用以监控内部活动的工具。
但是,监控内部的锁情况的工具一直支持的不好。
监控锁一个非常重要和常用的功能,在这篇文章,我讲阐述如何做到。
1介绍
假设有这样的一种情况:你准备update一个表,但是每次执行update语句的时候,都一直在等待,直到返回信息告诉你等待锁超时。
你准备update的表已经被某人锁住了,但是你不确定到底是谁。
这就有点郁闷了,因为你不知道现用者要用多久,是不是无限期的使用。
有时候我不得不隔天再update,这个表可能要被锁上一整天。
在MySQL中有一个方法可以探窥到锁情况,它会打印出所有innodb的信息:
mysql>SHOWENGINEINNODBSTATUS;
2哪里有死锁?
查看锁的第一步就是找到死锁的位置。
上面这个命令会显示关于死锁事务的信息,谁在使用锁,谁在等待锁。
下面是截取了一段输出,可以重点查看“WAITINGFORTHISLOCKTOBEGRANTED”和“HOLDSTHELOCKS.”部分:
------------------------ LATESTDETECTEDDEADLOCK ------------------------ 06073120:19:58 ***(1)TRANSACTION: TRANSACTION093698,ACTIVE2sec,processno12767,OSthreadid1141946720startingindexread mysqltablesinuse1,locked1 LOCKWAIT4lockstruct(s),heapsize1216 MySQLthreadid3,queryid19localhostrootUpdating updatetest.innodb_deadlock_makerseta=0wherea<>0 ***(1)WAITINGFORTHISLOCKTOBEGRANTED: RECORDLOCKSspaceid0pageno131120nbits72index`GEN_CLUST_INDEX`oftable`test/innodb_deadlock_maker`trxid093698lock_modeXwaiting Recordlock,heapno2PHYSICALRECORD:n_fields4;compactformat;infobits0 0:len6;hex000000019000;asc;;1:len6;hex000000016e01;ascn;;2:len7;hex80000000320110;asc2;;3:len4;hex80000000;asc;; ***(2)TRANSACTION: TRANSACTION093699,ACTIVE2sec,processno12767,OSthreadid1142212960startingindexread,threaddeclaredinsideInnoDB500 mysqltablesinuse1,locked1 4lockstruct(s),heapsize1216 MySQLthreadid4,queryid20localhostrootUpdating updatetest.innodb_deadlock_makerseta=1wherea<>1 ***(2)HOLDSTHELOCK(S): RECORDLOCKSspaceid0pageno131120nbits72index`GEN_CLUST_INDEX`oftable`test/innodb_deadlock_maker`trxid093699lockmodeS Recordlock,heapno1PHYSICALRECORD:n_fields1;compactformat;infobits0 0:len8;hex73757072656d756d;ascsupremum;; Recordlock,heapno2PHYSICALRECORD:n_fields4;compactformat;infobits0 0:len6;hex000000019000;asc;;1:len6;hex000000016e01;ascn;;2:len7;hex80000000320110;asc2;;3:len4;hex80000000;asc;; Recordlock,heapno3PHYSICALRECORD:n_fields4;compactformat;infobits0 0:len6;hex000000019001;asc;;1:len6;hex000000016e01;ascn;;2:len7;hex8000000032011f;asc2;;3:len4;hex80000001;asc;; ***(2)WAITINGFORTHISLOCKTOBEGRANTED: RECORDLOCKSspaceid0pageno131120nbits72index`GEN_CLUST_INDEX`oftable`test/innodb_deadlock_maker`trxid093699lock_modeXwaiting Recordlock,heapno2PHYSICALRECORD:n_fields4;compactformat;infobits0 0:len6;hex000000019000;asc;;1:len6;hex000000016e01;ascn;;2:len7;hex80000000320110;asc2;;3:len4;hex80000000;asc;; ***WEROLLBACKTRANSACTION(2)
以“RECORDLOCKSspaceid0”开头的一行比较重要,它指示哪个表的哪个索引被锁住了。
这是问题的关键所在,我们要找的就是这里。
但是还有一个问题,当我们知道有死锁的时候,说明已经太晚了。
我们不想知道过去谁拥有锁,我们只关心现在谁拥有锁。
但是,上面的死锁信息对于找到当前拥有锁的事务,依然是帮助不多。
3当事务在等待锁
接下来,我们可以看看事务部分的锁信息,如下:
---TRANSACTION093789802,ACTIVE19sec,processno9544,OSthreadid389120018 MySQLthreadid23740,queryid194861248worker1.office192.168.0.12robot ---TRANSACTION093789797,ACTIVE20sec,processno9537,OSthreadid389005359startingindexread mysqltablesinuse1,locked1 LOCKWAIT2lockstruct(s),heapsize320 MySQLthreadid23733,queryid194861215elpaso192.168.0.31robotUpdating updatetest.testsetcol1=4 -------TRXHASBEENWAITING20SECFORTHISLOCKTOBEGRANTED: RECORDLOCKSspaceid0pageno299998nbits200index`PRIMARY`oftable`test/test`trxid093789797lock_modeXlocksrecbutnotgapwaiting Recordlock,heapno77PHYSICALRECORD:n_fields15;compactformat;infobits0 0:len4;hex80474fd6;ascGO;;1:len6;hex000005970680;asc;;2:len7;hex000017c02b176c;asc+l;;3:len4;hex80000003;asc;;4:len8;hex800000000da0c93a;asc:;;5:len8;hex800000000eb2ea7e;asc~;;6:len4;hexc771fe44;ascqD;;7:len4;hex8000003e;asc>;;8:len8;hex8000123eb9e5dfd5;asc>;;9:len4;hex8000003a;asc:;;10:len8;hex8000123eb9e43603;asc>6;;11:len4;hex80000035;asc5;;12:len8;hex8000123eb9d6c130;asc>0;;13:len4;hex80000033;asc3;;14:len8;hex8000123eb9c7c853;asc>S;; --------------------- ---TRANSACTION093789679,ACTIVE31082sec,processno9535,OSthreadid388972583startingindexread,threaddeclaredinsideInnoDB6 mysqltablesinuse4,locked4 11614lockstruct(s),heapsize683328 MySQLthreadid23731,queryid194861117elpaso192.168.0.31robot
我们看到,第一个事务已经等待锁等了20秒,它同样标有对应的表和索引。
同样,上面还显示了当前有4个表在使用,4个表被锁住,但是输出信息没有说明具体是哪些表。
可以看出,这里有一些对我们有用的信息,但是并不多。
当我们遇到查询在等待锁时,知道在等待什么锁,以及哪些事务正在拥有锁,有时候并没有太大帮助。
不过比之什么都没有好一点,如果我们只是看到两个事务,那么肯定是一个拥有锁,一个等待锁。
在上面的输出当中,是否有看到令人毛骨悚然的地方?
连接23731的事务093789771,已经活动了8个半小时?!
要找到它的拥有者,用processlist,然后用kill杀死这个连接。
mysql>showfullprocesslists; mysql>kill1234;
换句话说,在innodb表遇到表锁,如果幸运的话,我们值看到一个其他的事务带有锁,
那么,它就极有可能是它锁住了你的请求。
英文原文:
- HowtoFindOutWhoIsLockingaTableinMySQL