喜爱DB的人都知,insert,update操作一般都要加锁,捕捉DB的锁,可有意思了。
如<<Java DB2那点事(一)>>所提到的那点点事,在四条线程的折磨下,可以幸运的捕捉到DB2加的行锁。可惜当时没有把捕捉到的数据存下来,等到今天心血来潮写这篇文章的时候,DB2的行锁已经悄悄离去了。
捕捉DB2的锁,并找出加锁的罪犯,有四个步骤,如下四句db2pd 开头的语句:
db2pd -d 【XXDB】 -locks show detail
--look up the TranHdl which Type and Mode and Sts is unnormal
db2pd -db 【XXDB】 -transactions
--grep by the TranHdl is find by -locks, and look up the AppHandl
db2pd -db 【XXDB】 -applications
--grep by the AppHandl which is find by transactions, and look up the Appid, L-AnchID, L-StmtUID
db2pd -db 【XXDB】 -dynamic | more
-- find where the L-AnchID, L-StmtUID match the application, the lock stmt will be found
-- db2 "list application" | grep 【Appid】
-- will find the application that helds the lock
这四句语句运行前, 请确保已经连接上数据库
db2pd -d 【XXDB】 -locks show detail 运行后,一般是检查Type and Mode and Sts 中显示的加了X锁的,对应的TranHdl,其运行效果如下:
Database Partition 0 -- Database 【XXDB】 -- Active -- Up 0 days 06:11:21
Locks:
Address TranHdl Lockname Type Mode Sts Owner Dur HoldCount Att ×××××××××
找到TranHdl 的值后,运行db2pd -db 【XXDB】 -transactions,在结果中找TranHdl对应的AppHandl,其运行效果如下:
Database Partition 0 -- Database 【XXDB】 -- Active -- Up 0 days 07:00:12
Transactions:
Address AppHandl [nod-index] TranHdl Locks State Tflag Tflag2 Firstlsn Lastlsn LogSpace SpaceReserved TID AxRegCnt GXID
0x0000000220291C80 456 [000-00456] 2 0 READ 0x00000000 0x00000000 0x000000000000 0x000000000000 0 0 0x0000003EDD28 1 0
0x0000000220292A80 1414 [000-01414] 3 0 READ 0x00000000 0x00000000 0x000000000000 0x000000000000 0 0 0x0000003ED89B 1 0
0x0000000220293880 250 [000-00250] 4 0 READ 0x00000000 0x00000000 0x000000000000 0x000000000000 0 0 0x0000003EEB9B 1 0
0x0000000220294680 334 [000-00334] 5 0 READ 0x00000000 0x00000000 0x000000000000 0x000000000000 0 0 0x0000003ED89F 1 0
0x0000000220295480 366 [000-00366] 6 0 READ 0x00000000 0x00000000 0x000000000000 0x000000000000 0 0 0x0000003ED8B2 1 0
找到AppHandl后继续运行db2pd -db 【XXDB】 -applications,在结果中找AppHandl对应的Appid, L-AnchID, L-StmtUID,其中Appid 就是加了锁的连接,通过 list application 可以找到对应的 Appl.Handle,这就是造成加了锁的连接,如果对它有意见,那就无情的杀掉它吧(force application([Appl.Handle]))。而L-AnchID, L-StmtUID则是我们下一步要找的依据。先来看看这个步骤运行的效果吧:
Database Partition 0 -- Database GDZMDB2 -- Active -- Up 0 days 07:14:10
Applications:
Address AppHandl [nod-index] NumAgents CoorPid Status C-AnchID C-StmtUID L-AnchID L-StmtUID Appid
0x00000002003012C0 366 [000-00366] 1 7073 UOW-Waiting 0 0 82 1 AC100ED7.G709.018244020635
0x00000002003011C0 334 [000-00334] 1 9394 UOW-Waiting 0 0 0 0 *LOCAL.DB2.091223223419
0x000000020022F1A0 250 [000-00250] 1 5325 ConnectCompleted 0 0 0 0 *LOCAL.DB2.091223223417
0x0000000200305CA0 1414 [000-01414] 1 9170 ConnectCompleted 0 0 0 0 *LOCAL.DB2.091223223416
0x000000020030FE80 456 [000-00456] 1 7348 UOW-Waiting 0 0 0 0 *LOCAL.db2inst1.091223223415
找到我们要的L-AnchID, L-StmtUID后,运行db2pd -db 【XXDB】 -dynamic | more,这句语句是要找出加锁的动态sql语句。对照L-AnchID, L-StmtUID的值,Text的值就是动态sql。运行效果如下:
Database Partition 0 -- Database GDZMDB2 -- Active -- Up 0 days 07:16:59
Dynamic Cache:
Current Memory Used 791182
Total Heap Size 3734732
Cache Overflow Flag 0
Number of References 5316
Number of Statement Inserts 382
Number of Statement Deletes 324
Number of Variation Inserts 83
Number of Statements 58
Dynamic SQL Statements:
Address AnchID StmtUID NumEnv NumVar NumRef NumExe Text
0x000000022C0A34A0 197 1 1 1 1 1 select sum(DURATION)
SUM,avg(DURATION) AVG,max(DURATION) MAX,count(*) CNT,classname, method from duty_perf_statis WHERE DURATION>0 group by
classname,method with ur
加红色字体部分就是执行的sql(这里不是加锁的例子)。
至此,我们已经能把导致加锁的连接和sql statement都找出来,接下来,兄弟, 知道怎么办了吧。
感谢这次性能调优引发的DB的锁的问题,感谢公司给我提供写日志的道具--一部电脑,一张桌子,一张凳子,还有灯光,水。
谢谢关注。