資料列版本控管 SnapShot Isolation V.S Read Committed Snapshot ( 一 )

資料列版本控管 SnapShot Isolation V.S Read Committed Snapshot ( 一 )

 

 

斯斯有兩種,而SQL在2005版後提供『資料列版本控管(Row Version)』也有兩種。

 

1.「快照集隔離(Snapshot Isolation)」

 

2.「讀取認可快照(Read Committed Snapshot)」

 

 

開啟資料列版本控管功能的好處就是可以降低Blocking及Deadlock的發生,其運作

 

方式就是會在tempdb建立一個快照讓單純執行查詢的Query直接去讀取Copy出來

 

Read Only的資料,而不會因為交易中資料尚未Commit而造成Blocking,讓其他單

 

純只是想Select的Query全部處於等待,造成效能上的問題。

 

 

啟用「快照集隔離(Snapshot Isolation)」的語法為:

ALTER DATABASE DB SET ALLOW_SNAPSHOT_ISOLATION ON

 

啟用「讀取認可快照(Read Committed Snapshot)」的語法為:

ALTER DATABASE DB SET READ_COMMITTED_SNAPSHOT ON

 

 

這一篇我們先來LAB一下「快照集隔離(Snapshot Isolation)」的功能

 

 

 

步驟一、首先我們先建立一資料庫SnapShotTest並開啟資料庫「快照集隔離

 

(Snapshot Isolation)」功能(如下圖所示)

clip_image002_thumb

 

 

步驟二、開啟一個Session編號59,然後在這一個Session開啟交易去Update Employees

 

資料表中EmployeeID為1的資料,將FirstName改為ROCK。記得先不要Commit此筆交易。

clip_image004_thumb

 

 

步驟三、我們再開一個ID 60的 Session,然後Select EmployeeID為1的那一筆資料。

 

如下圖所示,這一個Query會被Blocking住,而持續處於Waitting狀態。此時我們可

 

以知道即使我們有開啟資料庫的Snapshot Isolation,但是所有Session的預設Isolation

 

Level都還是Read Commit。

clip_image006_thumb

 

 

步驟四、我們在ID 60的Session中加入SET TRANSACTION ISOLATION LEVEL

 

SNAPSHOT語法,讓這一個Session使用Snapshot的Isolation Level(此時Session 59

 

 的Update交易一樣尚未Commit)。我們同樣Select EmployeeID為1的資料,會發

 

現可以順利取的資料而不會被Blocking住了。

clip_image008_thumb

 

 

 

步驟五、我們回到Session 59中,將交易Commit掉,確認將EmployeeID為1的

 

FirstName欄位改成ROCK。

 

clip_image010_thumb

 

 

 

步驟六、我們到Session 60中,此時不用再重複執行SET TRANSACTION ISOLATION

 

LEVEL SNAPSHOT語法了,執行過一次後這一個Session的Isolation Level就固定為Snapshot

 

了。這一次我們開啟交易(Begin Tran),然後一樣執行Select EmployeeID為1的語法。如下

 

圖所示,我們取得的資料FirstName欄位為ROCK,先不要將交易Commit。

clip_image012_thumb

 

 

 

步驟七、回到Session 59中,我們將EmployeeID為1的資料FirstName改為CAREY。

 

clip_image014_thumb

 

 

 

 

步驟八、我們在步驟七已經將欄位內容改為CAREY並且Commit了。此時再回到

 

Session 60來,這裡開啟的交易還沒Commit掉,我們重複再執行Select EmployeeID

 

為1的語法。會發現即使步驟七中資料修正過且Commit了,但在這裡我們取得的

 

欄位資料還是ROCK。

clip_image016_thumb

 

 

 

步驟九、此時我們再開一個Session為ID 61。一樣設定Isolation Level為Snapshot

 

並開啟交易然後Select EmployeeID為1的FirstName欄位資料。如下圖所示Session 61

 

取得的欄位資料是CAREY了,我們也不要將Session 61的交易結束掉。

clip_image018_thumb

 

 

 

 

 

步驟十、再次回到Session 59,並再一次將資料修改為DANIEL並且Commit交易。

 

clip_image020_thumb

 

 

 

步驟十一、我們回到Session 61再執行一次Select語法(如下圖),會發現資料回傳值仍為

 

CAREY。而Session 60再執行一次Select語法,資料回傳值仍為ROCK。

clip_image022_thumb

 

由上述幾個步驟可以發現針對每一個開啟的交易(注意Session要將Isolation Level設為Snapshot)

 

,SQL會產生相對應的資料列版本。

 

 

實驗中各Session的版本資料如下表 :

 

Session ID

FirstName資料

資料來源

59

DANIEL

Real Data

60

ROCK

Snapshot

61

CAREY

Snapshot

 

 

 

  

步驟十二、很重要須注意的一點,由於我們每一個Session都有其版本,因此實際的資料

 

也許已經被異動過好幾版了。Session 61中我們看見的資料是CAREY但實際上早被Session 59

 

改成DANIEL了,這時候我們如果在Session 61的交易中去Update EmployeeID為1的資料是會

 

失敗的(如下圖所示)。

clip_image024_thumb

 

 

小結 :

 

        啟動資料庫的ALLOW_SNAPSHOT_ISOLATION為ON,其Session的預設Isolation Level

 

還是Read Commit。必須在Session中執行SET TRANSACTION ISOLATION LEVEL SNAPSHOT

 

後將該Session的Isolation Level更改為Snapshot後才會有『資料列版本控管(Row Version)』的

 

功能。而要注意的地方就是交易中的新增、刪除、修改須注意錯誤控制。

 

 

 

我是ROCK

rockchang@mails.fju.edu.tw