SQL Server 並發控制 第三篇:隔離級別和行版本(2)


SQL Server 並發控制 第一篇:並發模式和事務

SQL Server 並發控制 第二篇:隔離級別和鎖(1)

SQL Server 並發控制 第三篇:隔離級別和行版本(2)

 

隔離級別定義事務處理數據讀取操作的隔離程度,隔離級別控制讀操作的行為。在樂觀並發模式下,使用行版本化技術,當對數據進行更新時,都會在tempdb中存儲該數據行的原始副本,術語叫作行版本(Row Version),把tempdb中存儲行版本的空間叫做版本庫。在修改操作發生時,SQL Server 創建一個Row Version,將原始數據復制到版本庫,Row Version是在修改操作之前已提交的數據。在數據更新期間,如果有其他讀操作要訪問該數據,那么它將讀取到數據的副本,並且不會阻塞寫操作。當寫操作完成時,釋放行版本。

總結,在樂觀並發模式下,使用行版本來保證事務的ACID屬性,當讀操作引用被其他事務更新,但尚未提交的數據時:

  • 對於寫操作,對正在更新的數據進行備份,把備份存儲到tempdb中。
  • 對於讀操作,從tempdb中讀取行版本,讀取在寫操作之前存儲的副本。

一,啟用基於快照的隔離級別

在樂觀並發模式下,有兩個基於快照的隔離級別,都使用行版本來維護讀操作的一致性:

  • snapshot 隔離級別,簡稱SI,實現事務級別的數據一致性,在同一個事務中,讀取到的數據是一致的,其行為和SERIALIZABLE隔離級別相同。
  • read committed snapshot 隔離級別,簡稱RCSI,實現語句級別的數據一致性,在同一事務中,可能讀取到的數據是不一致的。

1,啟用RCSI

在默認的隔離級別Read Committed下,使事務讀取Row Versioning數據,只需要把數據庫選項READ_COMMITTED_SNAPSHOT設置為ON:

ALTER DATABASE CURRENT 
SET READ_COMMITTED_SNAPSHOT ON 
WITH NO_WAIT; 

當啟用READ_COMMITTED_SNAPSHOT選項,意味着把數據庫的默認隔離級別設置為RCSI。如果禁用READ_COMMITTED_SNAPSHOT選項,意味着數據庫的默認隔離級別是悲觀並發模式下的READ COMMITTED隔離級別。

在RCSI隔離級別下,事務有兩個特性:

  • 事務使用行版本(Row version)代替加鎖,讀操作不會阻塞其他事務的寫操作;
  • RCSI隔離級別保證語句級別的事務一致性,查詢語句只能讀取在該語句執行時已經提交的數據,如果在該語句執行時數據更新尚未提交,該語句讀取不到。

2,啟用SI

使用快照隔離級別,必須分兩步來設置,第一步,設置數據庫選項 ALLOW_SNAPSHOT_ISOLATION 為 ON,但是該選項沒有改變Session-Level的事務隔離級別,第二步,需要修改Session-Level的事務隔離級別為SNAPSHOT,才能使用行版本數據。

step1,設置數據庫選項,允許快照隔離級別

ALTER DATABASE CURRENT 
SET ALLOW_SNAPSHOT_ISOLATION ON; 

step2,把會話的隔離級別設置為SNAPSHOT

把當前Session的隔離級別設置為Snapshot,事務才能訪問Row Versioning的數據:

SET TRANSACTION ISOLATION LEVEL SNAPSHOT

如果不把會話的隔離級別設置為SNAPSHOT,會話的隔離級別是悲觀模式下的READ COMMITTED。

二,基於快照的隔離級別

SQL Server 數據庫默認的事務隔離級別是Read Committed,會話默認的隔離級別是數據庫默認的隔離級別,即是Read Committed。但是會話默認的隔離級別受到數據庫選項 READ_COMMITTED_SNAPSHOT 的影響,該選項影響Read Committed 隔離級別是使用行版本控制事務的讀操作,還是使用加共享鎖來控制事務的讀操作。雖然用戶不能修改數據庫默認的隔離級別,但是用戶可以修改會話默認的隔離級別。

在默認的Read Committed隔離級別下,事務不能讀取被其他事務修改,但尚未提交的數據,即只能讀取已提交更新的數據:

  • 設置選項READ_COMMITTED_SNAPSHOT為OFF(默認設置),數據庫引擎使用Shared Lock阻止其他事務修改當前事務正在讀取的數據;當讀取被其他事務修改,但尚未提交更新的數據行時,該讀操作將被阻塞。
  • 設置選項READ_COMMITTED_SNAPSHOT為ON,數據庫引擎使用行版本化(Row Versioning)的數據實現語句級別的一致性,在執行讀操作時,事務不會申請共享鎖,不會阻塞其他事務的寫操作,但只能讀取已提交的數據。

1,READ COMMITTED Snapshot隔離級別

READ COMMITTED Snapshot隔離級別(簡稱RCSI)保證語句級別的讀一致性。當數據庫選項 READ_COMMITTED_SNAPSHOT 設置為ON,Read Committed隔離級別使用Row Version提供語句級別(Statement-Level)的讀一致性,即RCSI隔離級別。

在RCSI下,當一個事務開始運行在RCSI級別下,語句只會看到語句開始時的快照,當重新讀取同一個數據時,該數據可能被其他寫操作修改,也即是說,在同一個事務中,對同一個數據重復讀取,得到的值可能不同。

2,SANPSHOT隔離級別

另外一個基於快照的隔離級別是SANPSHOT隔離級別(簡稱SI),Snapshot隔離級別使用Row Version 實現事務級別(Transaction-Level)的讀一致性。在當前事務開始時,任何讀操作,都基於相同的數據snapshot。當讀取被其他事務修改的數據行時,讀操作只會看到事務開始時的快照,在同一個事務中,對取同一個數據重復讀取,得到的值是相同的。

在Snapshot隔離級別下,事務在修改任何數據之前,先將原始數據行復制到tempdb,創建數據行的一個原始版本(Row Version),注意,SQL Server只會復制被修改的數據行,對於未修改的數據行,不會保存行版本數據。后續其他事務的讀操作都去讀該復制的行版本。在Snapshot隔離級別下,讀寫操作不會互相阻塞,使用行版本控制能夠提高事務的並發性,但是有一個明顯的缺點,雖然用戶讀到的不是臟數據,但是數據可能正在被修改,很快就要過期。如果根據這個過期的數據做數據修改,可能會產生邏輯錯誤。

3,RCSI和SI的異同

相同點:在snapshot 和 read committed snpshot隔離級別下,事務讀取的數據都是已提交的;

不同點:RCSI保證語句級別的讀一致性,SI保證事務級別的讀一致性:

  • 事務級別的讀一致性是指:在事務開始,到事務提交期間,該事務持有數據的一個快照。如果在該事務活動期間,其他事務更新表數據,該事務只會讀取快照數據,不會讀取到被其他事務更新的數據值;
  • 語句級別的讀一致性是指:單個語句(single statement)看到的數據是一致性的;在當前事務活動期間,事務中的語句能夠讀取到被其他事務提交更新的數據值;例如,在語句stmt1執行時,事務沒有提交更新,stmt1看到Reader1的值是2;當語句stmt2執行時,事務提交更新,stmt2看到Reader2的值是3;

三,引用徐海蔚老師的例子,測試隔離級別的行為

 

snapshot隔離級別不會阻塞其他事務的寫操作,該隔離級別忽略數據的修改操作,只讀取row versioning的數據,就是說,讀取到的是數據修改之前的版本,當snapshot事務嘗試修改由其他事務修改的數據時,產生更新沖突,寫操作異常終止。

read committed snapshot隔離級別,讀取行版本化的已提交數據:

  • 當其他事務未提交更新時,讀取行版本化的數據,即讀取修改之前的數據值;
  • 當其他事務提交數據更新后,讀取修改后數據值;
  • 由於該隔離級別不會申請共享鎖,因此不會阻塞其他事務的更新操作;
  • 能夠更新由其他事務修改的數據;

四,Snapshot隔離級別

在SNAPSHOT隔離級別下,任何寫操作都會將更新之前的數據行保存到tempdb中,讀取操作要么從原始數據表中讀取數據,要么從tempdb中讀取行版本化的數據。Snapshot隔離級別指定:在一個事務中,任何語句讀取的數據,是事務一致性的版本。事務一致性是指在事務開始時,在表級別創建數據快照,只能識別其他事務已提交的數據更新。在事務開始之后,當前事務不會識別其他事務執行的數據更新。Sanpshot隔離級別實現事務級別的數據一致性。SQL Server 使用tempdb來存儲行版本化(row versioning)的數據,如果數據更新較多,存儲的行版本太多,會導致tempdb成為系統瓶頸。

1,在Snapshot隔離級別下,更新操作創建Row Version

一旦啟用Snapshot隔離級別,在事務中執行更新操作時,SQL Server將被更新的數據行的原始版本存儲在tempdb中,即在tempdb中保存數據行的原始數據,因此,讀操作獲取取行版本的數據,都是數據被更新之前的值。

2,Snapshot隔離實現事務一致性

Snapshot隔離級別實現事務級別的數據一致性,這意味着,在單個事務中的所有查詢語句,看到的是相同版本的數據。在Snapshot隔離級別下,事務在讀取數據不需要加行級鎖或頁級鎖,讀寫操作互不阻塞。

快照隔離級別使得讀操作不需要對基礎數據行或數據頁上施加共享鎖,這使其他寫事務不會被先前未完成的讀事務阻止。修改數據的事務不會阻止讀取數據的事務,並且讀取數據的事務不會阻止寫入數據的事務,這種非阻塞行為顯着降低了復雜事務發生死鎖的可能性。

3,Snapshot 使用樂觀並發模式

Snapshot隔離級別使用樂觀並發模式,如果一個Snapshot 事務嘗試去提交數據行的更新,但是該數據行已經被其他事務修改,並且修改的時間早於當前事務開始的時間,那么SQL Server將當前事務作為失敗者,並回滾其事務操作。樂觀並發模式用於沖突較少的環境中,如果應用程序在更新數據時經常發生沖突,Snapshot隔離級別可能不是最好的選擇。

 

參考文檔:

Snapshot Isolation in SQL Server

Isolation Levels in the Database Engine

SQL SERVER – Difference Between Read Committed Snapshot and Snapshot Isolation Level


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM