喜愛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的鎖的問題,感謝公司給我提供寫日誌的道具--一部電腦,一張桌子,一張凳子,還有燈光,水。
謝謝關注。