造成資料庫表死鎖的原因分析及解決方案
一、死鎖產生的原因
在聯機事務處理系統中,造成宕機主要有兩方面原因。一方面,由於多使用者、多工的併發性和事務的完整性要求,當多個事務處理對多個資源同時訪問時,若雙方已鎖定一部分資源但也都需要對方已鎖定的資源時,無法在有限的時間內完全獲得所需的資源,就會處於無限的等待狀態,從而造成其對資源需求的死鎖。
另一方面,資料庫本身加鎖機制的實現方法不同,各資料庫系統也會產生其特殊的死鎖情況。如在Sybase SQL Server 11中,最小鎖為2K一頁的加鎖方法,而非行級鎖。如果某張表的記錄數少且記錄的長度較短(即記錄密度高,如應用系統中的系統配置表或系統引數表就屬於此類表),被訪問的頻率高,就容易在該頁上產生死鎖。
二、容易發生死鎖的幾種情況如下:
1、不同的儲存過程、觸發器、動態SQL語句段按照不同的順序同時訪問多張表;
2、在交換期間新增記錄頻繁的表,但在該表上使用了非群集索引(non-clustered);
3、表中的記錄少,且單條記錄較短,被訪問的頻率較高;
4、整張表被訪問的頻率高(如程式碼對照表的查詢等)。
三、以上死鎖情況的對應解決方案
1、在系統實現時應規定所有儲存過程、觸發器、動態SQL語句段中,對多張表的操作總是使用同一順序。如:
有兩個儲存過程proc1、proc2,都需要訪問三張表zltab、z2tab和z3tab,如果proc1按照zltab、z2tab和z3tab的順序進行訪問,那麼,proc2也應該按照以上順序訪問這三張表。
2、對在交換期間新增記錄頻繁的表,使用群集索引(clustered),以減少多個使用者新增記錄到該表的最後一頁上,在表尾產生熱點,造成死鎖。這類表多為往來賬的流水錶,其特點是在交換期間需要在表尾追加大量的記錄,並且對已新增的記錄不做或較少做刪除操作。
3、對單張表中記錄數不太多,且在交換期間select或updata較頻繁的表可使用設定每頁最大行的辦法,減少資料在表中存放的密度,模擬行級鎖,減少在該表上死鎖情況的發生。這類表多為資訊繁雜且記錄條數少的表。如:
系統配置表或系統引數表。在定義該表時新增如下語句: with max_rows_per_page=1
4、在儲存過程、觸發器、動態SQL語句段中,若對某些整張表select操作較頻繁,則可能在該表上與其他訪問該表的使用者產生死鎖。對於檢查賬號是否存在, 但被檢查的欄位在檢查期間不會被更新等非關鍵語句,可以採用在select命令中使用at isolation read uncommitted子句的方法解決。該方法實際上降低了select語句對整張表的鎖級別,提高了其他使用者對該表操作的併發性。在系統高負荷執行時,該方法的效果尤為顯著。
如:select * from titles at isolation read uncommitted
對流水號一類的順序數生成器欄位,可以先執行updata流水號欄位+1,然後再執行select獲取流水號的方法進行操作。