【DB2】如何精確定位到死鎖
本次差旅發現過很多死鎖,有很多死鎖定位方式。但是能精確定位的還是比較少。通過本次差旅實踐,發現通過dbpd來捕捉是最好的,也是最精確的。方法我總結如下:
1) 啟用死鎖監控
db2pdcfg –catch deadlock
當死鎖觸發時,會自動執行db2cos指令碼(在%db2dump%/bin 目錄下)。這個腳本里呼叫了db2pd來將當前資訊捕捉下來,其中主要捕捉的資訊包含如下:
Db2pd共捕捉了locks(鎖)、transaction(事務)、agents(代理程序)、application(應用)、dynamic(動態sql,這個最重要,是用於定位到sql)
2) 坐等死鎖。當死鎖觸發時,將自動生成 db2cos.process_id_application_id.txt,該檔案在db2的診斷目錄下(可以通過 db2 get dbm cfg | grep “DIA”來獲取診斷目錄位置)
3) 分析db2cos檔案:
a) 首先看-locks showlocks 模組,截圖如下:
找到其中包含【Sts】為W*,並且根據【ReleaseFlg】定位到相同slot的,總共會有兩處,一處狀態為 W*(是死鎖)、一處是 G(代表鎖擁有)。Slot相同,就代表他們是在同一個資料物件上等待。尋找後的資料,如下截圖:
從上圖,可以看出如下資訊:
Ø 在tabled=514和tabspacesId=4上等待(可以在syscat.tables 檢視上根據資訊定位到表名稱 select TABNAME , TABSCHEMA from syscat.tables where TABLEID=514 and TBSPACEID=4)
Ø 佔據表鎖的transactionHandle Id 為 28,是X排他鎖
Ø 等待表鎖的transactionHandle Id為55,是NS(下一鍵共享鎖)
有了這兩個Id接著往下走。我們已經知道了誰在等待、誰在佔有。
b) 檢視-transaction,獲取transaction id對應的agent id
可以看到Apphandle對應值應有了,下面就需要根據這個Apphandle去找sql執行的資訊,已經離目標不遠了哈。
c) 檢視-dynamic 資訊
觀察如下列【C-AnchID】、【C-StmtUID】、【L-AnchID】、【L-StmtUID】
其中C-AnchID是代表當前正在執行的sql槽號,L-AnchID是代表上次執行的sql槽號。OK,我們就需要通過這個槽號來找到對應的Sql。定位到如下模組:
然後根據【C-AnchID】、【C-StmtUID】、【L-AnchID】、【L-StmtUID】列值找到對應sql(AnchID->C- AnchID,StmtUID-> C-StmtUID),如下:
自此,我們發現了導致死鎖的Sql:
哪個sql 在等待鎖?
狀態為W*:
SELECT COUNT ( * )
FROM BIZ.WF_TASK A
INNER JOIN
BIZ.REI_FORM B
ON A.RECEIPT_NO = B.REI_FORM_ID
WHERE A.TASK_STATUS = ?
AND A.HANDLE_ID = ?
AND A.RECEIPT_TYPE = ?
AND B.APPROVE_STATUS = ?
AND B.REI_FORM_NO = ?
哪個Sql在佔有鎖?
狀態為G:
UPDATE BIZ.REI_FORM
SET APPROVE_STATUS = ?
WHERE REI_FORM_ID = ?
整個過程截圖如下:
定位到Sql之後,我們就可以按照第三節中敘述的方法,該建索引就建立索引,sql寫的不規範就調整sql。