[SQL Server] 鎖定使用的藝術 (Part 2) - 隔離層次 (Isolation Level)

鎖定的另一種情況,就是當應用程式使用交易 (Transaction) 時,資料庫引擎會啟用交易處理的機制,在 BEGIN TRANS 至 COMMIT/ROLLBACK 間修改資料,在交易進行的期間資料庫引擎會依照適當的方式來進行交易相關資料的鎖定,而在交易之外的使用者讀取或寫入這些交易資料時,會受到交易鎖定行為的影響,資料庫引擎在交易進行期間除了要保障在交易內的所有資料變更都要符合 ACID 規範外,也要避免在交易外的其他並行存取的可能干擾,所以在資料庫引擎中都會設計一個在交易期間將交易資料與一般並行資料間的區隔機制,以保護交易中的資料以及其他並行作業間的交互動作,這個機制就是隔離層次。

鎖定的另一種情況,就是當應用程式使用交易 (Transaction) 時,資料庫引擎會啟用交易處理的機制,在 BEGIN TRANS 至 COMMIT/ROLLBACK 間修改資料,在交易進行的期間資料庫引擎會依照適當的方式來進行交易相關資料的鎖定,而在交易之外的使用者讀取或寫入這些交易資料時,會受到交易鎖定行為的影響,資料庫引擎在交易進行期間除了要保障在交易內的所有資料變更都要符合 ACID 規範外,也要避免在交易外的其他並行存取的可能干擾,所以在資料庫引擎中都會設計一個在交易期間將交易資料與一般並行資料間的區隔機制,以保護交易中的資料以及其他並行作業間的交互動作,這個機制就是隔離層次。

只要有修過資料庫系統的人,應該都會學到資料庫交易 (database transaction) 的一些理論與問題,其中一項就是當多人環境下的資料庫處理,有多個不同的交易對相同的資料進行異動,以及會針對該異動進行後續資料處理時,會遇到的可能問題,下圖就是一個典型例子:

image

這是一個很簡單的交易,乍看之下兩個交易並沒有相互影響,但如果是下圖的話,兩個交易間就會出現相互影響的狀況:

image

這在資料庫理論中被稱為交易排程 (transaction scheduling),資料庫引擎必須要能在兩個以上的交易同時進行時,自動決定能將兩個交易都順利完成的排程順序,這個排程演算法 (scheduling algorithm) 是交易隔離層次機制實作的其中一個部份,決定排程的動作稱為 Serializable (PS: 這個在台大和交大的資管研究所考試很愛考,給定兩個交易的動作,在不違反 ACID 原則下要找出正確的交易順序)。

隔離層次主要是要處理當交易正在進行時,其他的查詢或交易動作是否可以讀寫資料,或取得的資料是不是已經完成交易或未完成交易的狀態。在一個商業應用環境中,在交易中讀出的資料的正確性是非常重要的,舉個簡單的例子,在客戶下訂單時,庫存的數量會降低,但如果在處理庫存時剛好又有一支檢查配貨的程式進來檢查庫存數以決定進貨量,此時若配貨程式讀到的是交易未完成前的數值,那麼配貨的計算就會受到影響 (因為數字是錯的)。

前面所提的 Serializable 演算法是最穩固的一種隔離層次演算法,因為它強制所有的交易都必須按照順序,而且外部的查詢在 Serialize 的交易結束前,都不能讀取在交易中被鎖定住的資源 (資料列或資料表),這對資料正確性的保障是最完整的,但它因為鎖定了大範圍的資源,會對多人環境的資料庫效能造成影響,死結 (deadlock) 的機率也會提高。

SQL-92 規範中有提出四種交易的隔離層次,除了 Serializable 外,還有下列三種 (SQL Server 全都支援):

  • Read Uncommitted:允許其他查詢在交易未完成時,就可以讀取交易範圍內的資源,這個層次會鎖定的範圍非常小 (幾乎不定),在多人環境下可以完成忽略交易可能造成的損耗,但卻會有很嚴重的 Dirty Read 問題。
  • Read Committed:只允許其他查詢讀取已認可 (Committed) 的交易資料,這個層次會在交易認可前鎖定資源,認可後就釋放,它的優點是鎖定範圍小,對效能影響不大,而且可以保證資料的修改是已認可的,但它卻有可能會發生幽靈讀取 (Phantom Read) 的狀況,且它也會有不可重覆讀取 (Nonrepeatable read) 的問題。
  • Repeatable Read:有時交易執行的範圍會很長,且可能在交易內重覆參考某些資源,這種時候如果外部交易修改了交易內的參考資源時,就會發生資料不一致的問題,而這個隔離層次就是在避免這個問題,它具有 Read Committed 的特性,但又不允許其他交易修改交易內參考到的資源,以保證資料是可重覆讀取 (Repeatable Read) 的

除了上述四種層次外,在 SQL Server 2005 起又加入了一個新的層次,稱為 Snapshot Isolation,它最大的特色就是在交易進行前會複製交易內相關的資源的資料到 tempdb 中,所有交易會在這個複本中進行,所以原本的資料讀取不會受到鎖定影響,而在多個交易同時進行時,Snapshot 會使用資料列版本 (row version) 的識別機制來判斷認可交易時的寫入順序,也因為它是在副本中進行,所以不會發生 Dirty Read, Nonrepeatable Read 與 Phantom Read 的狀態,Snapshot Isolation 的本身是樂觀鎖定,所以在資源鎖定的範圍也不會太大。

下表為不同的交易隔離層次可能會發生的一些問題與交互作用的表格:

image

備註:

  • Dirty Read:意指在交易外的查詢讀到的資料會不一致,這是因為交易在認可前被讀了一次 (r1),交易中修改了該值,而修改後認可前又被讀了一次 (r2),而這兩個值不一致 (r1 != r2)。
  • Phantom Read: 意指在查詢讀到的資料在資料表中不存在,這會發生在 INSERT 和 DELETE 的狀況,例如交易進行時有新增資料或刪除資料,而外部查詢在交易完成前要查詢這筆新資料,或是在交易刪除資料後又可讀到被刪除的資料時,就是 Phantom Read 的錯誤狀態。

 

Reference:

Fundamental of Database Systems: Database Transaction Concept and Theory
SQL Server Books Online: Transaction Chapter