死結

當二或多個工作各自具有某個資源的鎖定,但其他工作嘗試要鎖定此資源,而造成工作永久封鎖彼此時,會發生死結。例如:

  • 交易 A 取得資料列 1 的共用鎖定。

  • 交易 B 取得資料列 2 的共用鎖定。

  • 交易 A 現在要求資料列 2 的獨佔鎖定,但會被封鎖直到交易 B 完成並釋出對資料列 2 的共用鎖定為止。

  • 交易 B 現在要求資料列 1 的獨佔鎖定,但會被封鎖直到交易 A 完成並釋出對資料列 1 的共用鎖定為止。

等到交易 B 完成後,交易 A 才能完成,但交易 B 被交易 A 封鎖了。這個狀況也稱為「循環相依性」(Cyclic Dependency)。交易 A 相依於交易 B,並且交易 B 也因為相依於交易 A 而封閉了這個循環。

在死結中的這兩個交易會一直等下去,除非由外部處理序解除此死結。Microsoft SQL Server Database Engine 死結監視器會定期檢查死結中的工作。如果監視器偵測到循環相依性,它會選擇其中一個工作作為犧牲者,以錯誤來結束其交易。這樣另一個工作便可以完成其交易。因為錯誤而結束交易的應用程式可以重試交易,通常在另一個死結交易完成之後便會完成。

在應用程式中使用特定的編碼慣例,會減少應用程式發生死結的機會。如需詳細資訊,請參閱<將死結數量降至最低>。

死結通常會和一般的封鎖產生混淆。當交易要求鎖定的資源被另一個交易鎖定時,提出要求的交易會等待鎖定釋出。依預設,除非設定了 LOCK_TIMEOUT,否則 SQL Server 交易不會逾時。提出要求的交易會被封鎖,但非死結,因為提出要求的交易尚未封鎖目前擁有鎖定的交易。最後,主控交易會完成並釋出鎖定,然後提出要求的交易會被授與鎖定並繼續進行。

死結 (Deadlock) 有時也稱為致命環節 (Deadly Embrace)。

死結可能發生在任何具有多執行緒的系統上,而不只是在關聯式資料庫管理系統,並且可能發生在資料庫物件鎖定之外的資源。例如,在多執行緒作業系統中的一個執行緒可能取得一或多個資源,像是記憶體區塊。若要取得的資源目前為另一個執行緒所擁有,前者的執行緒可能就必須等候擁有資源的執行緒釋放目標資源。等候的執行緒便是所謂的與擁有該特定資源的執行緒具有依存性。在 Database Engine 的執行個體中,當工作階段取得非資料庫資源 (例如記憶體或執行緒) 時,可能會發生死結。

顯示交易死結的圖表

在上圖中,在 Part 資料表鎖定資源上,交易 T1 相依於交易 T2。同樣的,在 Supplier 資料表鎖定資源上,交易 T2 相依於交易 T1。由於這些相依性形成循環,交易 T1 與 T2 之間便構成死結。

當資料表已分割,而且 ALTER TABLE 的 LOCK_ESCALATION 設定為 AUTO 時,也可能會發生死結。當 LOCK_ESCALATION 設定為 AUTO 時,可讓 Database Engine 鎖定 HoBT 層級 (而不是 TABLE 層級) 上的資料表資料分割來增加並行。但是,當個別交易在資料表中保留資料分割鎖定,而且想要鎖定其他交易資料分割上的某個地方時,這就會造成死結。您可以將 LOCK_ESCALATION 設定為 TABLE 來避免這種類型的死結;雖然這項設定會藉由強制資料分割的大量更新等候資料表鎖定,因而減少並行。