1. 程式人生 > >併發delete導致oracle死鎖問題的解決

併發delete導致oracle死鎖問題的解決

   專案中有一個批處理任務,用來刪除資料庫中過期的資料(包括說話人的語音、模型、記錄等),當程式被分散式部署後,就會有多個批處理執行緒同時進行刪除,不過不同的執行緒,會根據元資訊表得到不同的說話人資訊,從而刪除不同的資料,並不存在競爭的問題,但是,當專案使用oracle資料庫在線上執行時,卻頻繁出現了ORA-00060: deadlock detected while waiting for resource的錯誤。在進行錯誤除錯時,打印出了sql語句,發現程式在delete from smb.voice where id = ?時出現了deadlock,根據打印出的資訊,發現併發的執行緒刪除的voice id沒有重疊的現象,id為主鍵,根據id來刪除具體的行記錄,獲取到的應該為行鎖,兩個併發併發執行緒不會產生鎖競爭,為什麼會出現deadlock,非常鬱悶。

   於是登入oracle資料庫去檢視trace file,在trace file中發現了deadlock的相關資訊,如下:


   從上述資訊可以看出,兩個session都holds SX(行級排他鎖),在waits SSX(共享行級排他鎖),因為我對SX鎖我知道,根據id來刪除記錄,會產生SX排它鎖,正常,不過,它們等待的SSX鎖到底是什麼?通過查詢,我知道SSX同一時間只允許一個事務持有和修改鎖定的表,其他事務可以查詢但不能修改,也就是說SSX是表級別的鎖,這也就是此處deadlock的罪魁禍首,但是為什麼會出現表鎖喃?又是鎖住哪張表的喃?我無法根據上面的資訊,看出鎖住的是哪張表?就用一些資訊進行了google,發現了一個頁面上描述的問題的trace file和我的很像,網站:https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:3932525800346405986,而下面的解決方案中有如下資訊:

do you

1) delete from the parent table
2) update the parent table primary key (even if just setting it to itself, many applications do that for some reason)
3) merge into the parent table.

2)、3)的情況我都不存在,但是我要delete的voice表確實是主表(parent table),它被另一張記錄表verification_record表所依賴(利用外來鍵進行依賴),於是我開始研究外來鍵與deadlock之間的關係。發現了一個現象:oracle中外來鍵不加索引,當對主表進行操作時,會產生死鎖。因為當表之間存在外來鍵約束時,你對主表進行更新或刪除操作時,都會去全表掃描子表,找到外來鍵列的行記錄,確保資料的一致性,這樣就產生了SSX鎖,解決的方案為在子表的外來鍵列加索引,這樣掃描索引即可,不會全表掃描,也就不會產生SSX鎖,但是因為在我們的系統的主業務流程中,資料的插入操作很頻繁,建立過多索引會嚴重影響主業務的效率,於是我們取消了資料庫的外來鍵約束,由程式確保資料表的一致性,問題解決。