轉:數據庫的快照隔離級別(Snapshot Isolation) 數據庫的快照隔離級別(Snapshot Isolation) 數據庫的快照隔離級別(Snapshot Isolation)

數據庫的快照隔離級別(Snapshot Isolation)

 

隔離級別定義事務處理數據讀取操做的隔離程度,在SQL Server中,隔離級別只會影響讀操做申請的共享鎖(Shared Lock),而不會影響寫操做申請的互斥鎖(Exclusive Lock),隔離級別控制讀操做的行爲:html

  • 在讀數據時是否使用共享鎖,申請何種類型的鎖;
  • 事務持有讀鎖的時間;
  • 讀操做引用被其餘事務更新,但還沒有提交的數據行時,控制讀操做的行爲:
    • 被阻塞,等待其餘事務釋放互斥鎖;
    • 獲取更新以前的數據值,從tempdb中讀取行版本,該行版本在事務開始時已經提交;Retrieves the committed version of the row that existed at the time the statement or transaction started.
    • 讀沒有提交的數據,獲取更新以後的數據值;

在執行寫操做時,事務老是持有互斥鎖,直到事務結束才釋放,互斥鎖不受事務隔離級別的影響。在SQL Server中,互斥鎖和任意鎖都不兼容,在同一時間,同一個數據行上,只能有一個事務持有互斥鎖,就是說,寫操做是順序進行的,徹底隔離的,不能併發執行。隔離和併發,此消彼長。sql

Choosing a transaction isolation level does not affect the locks acquired to protect data modifications. A transaction always gets an exclusive lock on any data it modifies, and holds that lock until the transaction completes, regardless of the isolation level set for that transaction. 數據庫

事務的隔離級別共有5個,使用SET命令修改Session-Level的隔離級別,使用DBCC UserOptions 查看當前Session的隔離級別:併發

SET TRANSACTION ISOLATION LEVEL
     READ UNCOMMITTED
    | READ COMMITTED
    | REPEATABLE READ
    | SNAPSHOT
    | SERIALIZABLE

DBCC UserOptions
View Code

一,事務的隔離級別less

SQL Server 數據庫級別默認的事務隔離級別是Read Committed,用戶不能修改Database-Level默認的隔離級別,可是,用戶可以修改Session-Level默認的事務隔離級別。Session-Level默認的事務隔離級別是Read Committed,該隔離級別受到數據庫選項 READ_COMMITTED_SNAPSHOT 的影響,決定Read Committed隔離級別是使用行版本控制事務的讀操做,仍是使用加共享鎖來控制事務的讀操做,在默認的Read Committed隔離級別下:ide

  • 若是設置選項READ_COMMITTED_SNAPSHOT爲OFF,那麼事務在執行讀操做時申請共享鎖,阻塞其餘事務的寫操做;
  • 若是設置選項READ_COMMITTED_SNAPSHOT爲ON,那麼事務在執行讀操做時使用Row Versioning,不會申請共享鎖,不會阻塞其餘事務的寫操做;

在任何隔離級別下,事務在執行寫操做時都申請互斥鎖(exclusive lock),持有互斥鎖直到事務結束,互斥鎖不受隔離級別的控制;而共享鎖(Shared Lock)受到隔離級別的控制,隔離級別影響Shared Lock的申請和釋放:post

  • 在 Read Uncommitted隔離級別下,讀操做不會申請Shared Lock;
  • 在 Read Committed(不使用row-versioning),Repeatable Read 和 Serializable隔離級別下,都會申請Shared Lock;
  • 在 Read Committed(不使用row-versioning) 隔離級別下,在讀操做執行時,申請和持有Share Lock;一旦讀操做完成,釋放Shared Lock;
  • 在 Repeatable Read 和 Serializable隔離級別下,事務會持有Shared Lock,直到事務結束(提交或回滾);
  • 在Serializable隔離級別下,事務會持有範圍Shared Lock(Range Lock),鎖定一個範圍,在事務活躍期間,其餘事務不容許在該範圍中進行更新(Insert 或 delete)操做;

SQL Server支持使用Row Version的隔離級別,事務的讀操做只申請SCH-S 表級鎖,不會申請Page 鎖和Row 鎖,事務的修改操做仍然申請鎖測試

  • 當數據庫選項 READ_COMMITTED_SNAPSHOT 設置爲ON,Read Committed隔離級別使用Row Version提供語句級別(Statement-Level)的讀一致性;
    • When a transaction runs at the read committed isolation level, all statements see a snapshot of data as it exists at the start of the statement. 
  • Snapshot隔離級別使用Row Version 提供事務級(Transaction-Level)的讀一致性。在當前事務開始時,任何讀操做,都基於相同的數據庫snapshot。當讀取被其餘事務修改的數據行時,從tempdb中獲取行版本數據。使用Snapshot隔離級別時,必須設置數據庫選項ALLOW_SNAPSHOT_ISOLATION爲ON;
    • When reading rows modified by another transaction, they retrieve the version of the row that existed when the transaction started.
  • 在snapshot 和 read committed snpshot隔離級別下,事務讀取的數據都是已提交的;
  • 注意語句級別的讀一致性和事務級別的讀一致性是snapshot 和 read committed snpshot 最大的區別:
    • 事務級別的讀一致性是指:在事務開始,到事務提交期間,該事務持有數據的一個快照。若是在該事務活動期間,其餘事務更新表數據,該事務只會讀取快照數據,不會讀取到被其餘事務更新的數據值;
    • 語句級別的讀一致性是指:單個語句(single statement)看到的數據是一致性的;在當前事務活動期間,事務中的語句可以讀取到被其餘事務提交更新的數據值;例如,在語句stmt1執行時,事務沒有提交更新,stmt1看到Reader1的值是2;當語句stmt2執行時,事務提交更新,stmt2看到Reader2的值是3;

二,使用行版本(Row Version)的隔離級別ui

在默認的隔離級別Read Commited下,在執行讀操做時,事務申請shared lock,讀寫操做相互阻塞。在隔離級別Read Uncommitted下,事務不會申請shared lock,所以讀操做不會阻塞寫操做,可是讀操做可能會讀到髒數據。髒數據是指被其它還沒有提交的事務修改以後的數據值,不是指更新以前的數據值。url

行版本是指存儲在tempdb中,含有數據行和TSN的數據。數據表的一個Data Row,能夠有多個Row Version。修改操做發生時,SQL Server 建立一個Row Version,將Original Row複製到Row Version,並將當前事務的TSN也存儲在Row Version中。所以,Row Version存儲的是修改以前的數據值。

SQL Server 提供Snapshot隔離級別,用於讀取修改以前的數據值。在Snapshot隔離級別下,事務在修改任何數據以前,先將原始數據行復制到tempdb,建立數據行的一個原始版本(Row Version),注意,SQL Server只會複製被修改的數據行,對於未修改的數據行,不會保存行版本數據。後續其餘事務的讀操做都去讀該複製的行版本。在Snapshot隔離級別下,讀寫操做不會互相阻塞,使用行版本控制可以提升事務的併發性,可是有一個明顯的缺點,雖然用戶讀到的不是髒數據,可是數據可能正在被修改,很快就要過時。若是根據這個過時的數據作數據修改,可能會產生邏輯錯誤。

1,啓用Snapshot隔離級別

設置數據庫選項 ALLOW_SNAPSHOT_ISOLATION 爲 ON,沒有改變Session-Level的事務隔離級別,須要修改Session-Level的事務隔離級別爲SNAPSHOT,才能使用行版本數據

alter database current
set allow_snapshot_isolation on;

在使用Snapshot隔離級別時,必須將當前Session的隔離級別設置爲Snapshot,只有這樣,當前事務才能訪問Row Versioning的數據:

SET TRANSACTION ISOLATION LEVEL SNAPSHOT

2,數據庫選項READ_COMMITTED_SNAPSHOT(簡稱RCS)

在默認的隔離級別Read Committed下,使事務可以訪問Row Versioning數據,須要將數據庫選項READ_COMMITTED_SNAPSHOT設置爲ON:

alter database current
set allow_snapshot_isolation on;

alter database current 
set read_committed_snapshot on;

前提是必須設置數據庫選項ALLOW_SNAPSHOT_ISOLATION爲ON;一旦啓用RCS選項,在默認的Read Committed 隔離級別中,事務訪問版本化的數據行。在RCS隔離級別下,事務有兩個特性:

  • 事務使用行版本(Row version)代替加鎖,讀操做不會阻塞其餘事務的寫操做;
  • RCS隔離級別保證語句級別的事務一致性,查詢語句只能讀取在該語句執行時已經提交的數據,若是在該語句執行時數據更新還沒有提交,該語句讀取不到;

3,READ COMMITTED Snapshot隔離級別

在Read Committed 隔離級別下,事務不能讀取被其餘事務修改,但還沒有提交的數據,即只能讀取已提交更新的數據,READ COMMITTED隔離級別的行爲受到數據庫選項:READ_COMMITTED_SNAPSHOT的影響:

  • 若是設置RCS選項爲OFF(默認設置),數據庫引擎使用Shared Lock阻止其餘事務修改當前事務正在讀取的數據;當讀取被其餘事務修改,但還沒有提交更新的數據行時,該讀操做將被阻塞;
    • If READ_COMMITTED_SNAPSHOT is set to OFF (the default), the Database Engine uses shared locks to prevent other transactions from modifying rows while the current transaction is running a read operation. The shared locks also block the statement from reading rows modified by other transactions until the other transaction is completed.
  • 若是設置RCS選項爲ON,數據庫引擎使用行版本化(Row Versioning)的數據實現語句級別的一致性,不會阻塞其餘事務的寫操做,但只能讀取已提交更新的數據
    • If READ_COMMITTED_SNAPSHOT is set to ON, the Database Engine uses row versioning to present each statement with a transactionally consistent snapshot of the data as it existed at the start of the statement. Locks are not used to protect the data from updates by other transactions.

三,啓用快照隔離級別

1,使用snapshot 隔離級別

step1,設置數據庫選項

ALTER DATABASE CURRENT SET SINGLE_USER 
WITH ROLLBACK IMMEDIATE; ALTER DATABASE CURRENT SET ALLOW_SNAPSHOT_ISOLATION ON; --ALTER DATABASE CURRENT SET READ_COMMITTED_SNAPSHOT OFF; ALTER DATABASE CURRENT SET MULTI_USER;

step2,修改Session-Level的隔離級別爲snapshot

set transaction isolation level snapshot

2,使用Read_Committed_Snapshot隔離級別

ALTER DATABASE CURRENT SET SINGLE_USER 
WITH ROLLBACK IMMEDIATE; 
ALTER DATABASE CURRENT SET ALLOW_SNAPSHOT_ISOLATION ON; 
ALTER DATABASE CURRENT SET READ_COMMITTED_SNAPSHOT ON; 
ALTER DATABASE CURRENT SET MULTI_USER;

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

 

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

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

  • 當其餘事務未提交更新時,讀取行版本化的數據,即讀取修改以前的數據值;
  • 當其餘事務提交數據更新後,讀取修改後數據值;
  • 因爲該隔離級別不會申請共享鎖,所以不會阻塞其餘事務的更新操做;
  • 可以更新由其餘事務修改的數據;

五,Snapshot隔離級別(翻譯MSDN)

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

Specifies that data read by any statement in a transaction will be the transactionally consistent version of the data that existed at the start of the transaction. The transaction can only recognize data modifications that were committed before the start of the transaction. Data modifications made by other transactions after the start of the current transaction are not visible to statements executing in the current transaction. The effect is as if the statements in a transaction get a snapshot of the committed data as it existed at the start of the transaction.

1,在Snapshot隔離級別下,更新操做建立Row Version

一旦啓用Snapshot隔離級別,在事務中執行更新操做時,SQL Server將被更新的數據行的原始版本存儲在tempdb中,即在tempdb中保存數據行的Original data,所以,讀取行版本的數據,都只能讀取到數據行被更新以前的值。每個事務都擁有一個惟一的,遞增的順序號,記做TSN(Transaction Sequence Number),TSN可以惟一標識一個事務,每個行版本都存儲一個TSN,標識建立該行版本的事務。

Once snapshot isolation is enabled, updated row versions for each transaction are maintained in tempdb. A unique transaction sequence number identifies each transaction, and these unique numbers are recorded for each row version.

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

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

The term "snapshot" reflects the fact that all queries in the transaction see the same version, or snapshot, of the database, based on the state of the database at the moment in time when the transaction begins. No locks are acquired on the underlying data rows or data pages in a snapshot transaction, which permits other transactions to execute without being blocked by a prior uncompleted transaction. Transactions that modify data do not block transactions that read data, and transactions that read data do not block transactions that write data, as they normally would under the default READ COMMITTED isolation level in SQL Server. This non-blocking behavior also significantly reduces the likelihood of deadlocks for complex transactions.

3,Snapshot 使用樂觀併發模式

Snapshot隔離級別使用樂觀併發模式,若是一個Snapshot 事務嘗試去提交數據行的更新,可是該數據行已經被其餘事務修改,而且修改的時間早於當前事務開始的時間,那麼SQL Server將當前事務做爲失敗者,並回滾其事務操做。樂觀併發模式用於衝突較少的環境中,若是Application在更新數據時常常發生衝突,Snapshot隔離級別可能不是最好的選擇。

Snapshot isolation uses an optimistic concurrency model. If a snapshot transaction attempts to commit modifications to data that has changed since the transaction began, the transaction will roll back and an error will be raised. 

4,Snapshot 隔離和 Row Version的工做模式

當啓用Snapshot隔離級別時,每個更新數據的操做都會在tempdb中存儲該行的原始副本,術語叫做行版本(RowVersion),SQL Server爲每一個行版本添加事務的TSN,該TSN可以惟一標識更新操做所在的事務。讀操做在讀數據時,按照如下順序進行:

  • 建立一個新的事務,爲其分配TSN,一個惟一,遞增的序號;
  • snapshot事務從數據表中讀取數據行,從tempdb中讀取行版本(row version),該行版本的TSN最接近當前事務的TSN,但比當前事務的TSN小;
  • 在建立Snapshot時,從已提交的事務中獲取行版本數據,若是行版本數據標識的事務還沒有提交,那麼從更早的事務中獲取已提交更新的數據;
  • 事務從tempdb中讀取行版本數據,事務不會看到新插入的數據,由於插入數據的TSN比當前事務的TSN大;
  • 事務可以看到被其餘事務刪除的數據,前提是刪除數據的事務的TSN比當前事務的TSN大,這是由於其餘事務將行版本保存到tempdb中,當前事務從tempdb中讀取行版本數據;

When the SNAPSHOT isolation level is enabled, each time a row is updated, the SQL Server Database Engine stores a copy of the original row in tempdb, and adds a transaction sequence number to the row. The following is the sequence of events that occurs:

  • A new transaction is initiated, and it is assigned a transaction sequence number.

  • The Database Engine reads a row within the transaction and retrieves the row version from tempdb whose sequence number is closest to, and lower than, the transaction sequence number.

  • The Database Engine checks to see if the transaction sequence number is not in the list of transaction sequence numbers of the uncommitted transactions active when the snapshot transaction started.

  • The transaction reads the version of the row from tempdb that was current as of the start of the transaction. It will not see new rows inserted after the transaction was started because those sequence number values will be higher than the value of the transaction sequence number.

  • The current transaction will see rows that were deleted after the transaction began, because there will be a row version in tempdb with a lower sequence number value.

The net effect of snapshot isolation is that the transaction sees all of the data as it existed at the start of the transaction, without holding or placing any locks on the underlying tables. This can result in performance improvements in situations where there is contention.

A snapshot transaction always uses optimistic concurrency control, with holding any locks that would prevent other transactions from updating rows. If a snapshot transaction attempts to commit an update to a row that was changed after the transaction began, the transaction is rolled back, and an error is raised.

 

參考文檔:

Snapshot Isolation in SQL Server

Isolation Levels in the Database Engine

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

 

 

 

數據庫的快照隔離級別(Snapshot Isolation)

 

隔離級別定義事務處理數據讀取操做的隔離程度,在SQL Server中,隔離級別只會影響讀操做申請的共享鎖(Shared Lock),而不會影響寫操做申請的互斥鎖(Exclusive Lock),隔離級別控制讀操做的行爲:

  • 在讀數據時是否使用共享鎖,申請何種類型的鎖;
  • 事務持有讀鎖的時間;
  • 讀操做引用被其餘事務更新,但還沒有提交的數據行時,控制讀操做的行爲:
    • 被阻塞,等待其餘事務釋放互斥鎖;
    • 獲取更新以前的數據值,從tempdb中讀取行版本,該行版本在事務開始時已經提交;Retrieves the committed version of the row that existed at the time the statement or transaction started.
    • 讀沒有提交的數據,獲取更新以後的數據值;

在執行寫操做時,事務老是持有互斥鎖,直到事務結束才釋放,互斥鎖不受事務隔離級別的影響。在SQL Server中,互斥鎖和任意鎖都不兼容,在同一時間,同一個數據行上,只能有一個事務持有互斥鎖,就是說,寫操做是順序進行的,徹底隔離的,不能併發執行。隔離和併發,此消彼長。

Choosing a transaction isolation level does not affect the locks acquired to protect data modifications. A transaction always gets an exclusive lock on any data it modifies, and holds that lock until the transaction completes, regardless of the isolation level set for that transaction. 

事務的隔離級別共有5個,使用SET命令修改Session-Level的隔離級別,使用DBCC UserOptions 查看當前Session的隔離級別:

SET TRANSACTION ISOLATION LEVEL
     READ UNCOMMITTED
    | READ COMMITTED
    | REPEATABLE READ
    | SNAPSHOT
    | SERIALIZABLE

DBCC UserOptions
View Code

一,事務的隔離級別

SQL Server 數據庫級別默認的事務隔離級別是Read Committed,用戶不能修改Database-Level默認的隔離級別,可是,用戶可以修改Session-Level默認的事務隔離級別。Session-Level默認的事務隔離級別是Read Committed,該隔離級別受到數據庫選項 READ_COMMITTED_SNAPSHOT 的影響,決定Read Committed隔離級別是使用行版本控制事務的讀操做,仍是使用加共享鎖來控制事務的讀操做,在默認的Read Committed隔離級別下:

  • 若是設置選項READ_COMMITTED_SNAPSHOT爲OFF,那麼事務在執行讀操做時申請共享鎖,阻塞其餘事務的寫操做;
  • 若是設置選項READ_COMMITTED_SNAPSHOT爲ON,那麼事務在執行讀操做時使用Row Versioning,不會申請共享鎖,不會阻塞其餘事務的寫操做;

在任何隔離級別下,事務在執行寫操做時都申請互斥鎖(exclusive lock),持有互斥鎖直到事務結束,互斥鎖不受隔離級別的控制;而共享鎖(Shared Lock)受到隔離級別的控制,隔離級別影響Shared Lock的申請和釋放:

  • 在 Read Uncommitted隔離級別下,讀操做不會申請Shared Lock;
  • 在 Read Committed(不使用row-versioning),Repeatable Read 和 Serializable隔離級別下,都會申請Shared Lock;
  • 在 Read Committed(不使用row-versioning) 隔離級別下,在讀操做執行時,申請和持有Share Lock;一旦讀操做完成,釋放Shared Lock;
  • 在 Repeatable Read 和 Serializable隔離級別下,事務會持有Shared Lock,直到事務結束(提交或回滾);
  • 在Serializable隔離級別下,事務會持有範圍Shared Lock(Range Lock),鎖定一個範圍,在事務活躍期間,其餘事務不容許在該範圍中進行更新(Insert 或 delete)操做;

SQL Server支持使用Row Version的隔離級別,事務的讀操做只申請SCH-S 表級鎖,不會申請Page 鎖和Row 鎖,事務的修改操做仍然申請鎖

  • 當數據庫選項 READ_COMMITTED_SNAPSHOT 設置爲ON,Read Committed隔離級別使用Row Version提供語句級別(Statement-Level)的讀一致性;
    • When a transaction runs at the read committed isolation level, all statements see a snapshot of data as it exists at the start of the statement. 
  • Snapshot隔離級別使用Row Version 提供事務級(Transaction-Level)的讀一致性。在當前事務開始時,任何讀操做,都基於相同的數據庫snapshot。當讀取被其餘事務修改的數據行時,從tempdb中獲取行版本數據。使用Snapshot隔離級別時,必須設置數據庫選項ALLOW_SNAPSHOT_ISOLATION爲ON;
    • When reading rows modified by another transaction, they retrieve the version of the row that existed when the transaction started.
  • 在snapshot 和 read committed snpshot隔離級別下,事務讀取的數據都是已提交的;
  • 注意語句級別的讀一致性和事務級別的讀一致性是snapshot 和 read committed snpshot 最大的區別:
    • 事務級別的讀一致性是指:在事務開始,到事務提交期間,該事務持有數據的一個快照。若是在該事務活動期間,其餘事務更新表數據,該事務只會讀取快照數據,不會讀取到被其餘事務更新的數據值;
    • 語句級別的讀一致性是指:單個語句(single statement)看到的數據是一致性的;在當前事務活動期間,事務中的語句可以讀取到被其餘事務提交更新的數據值;例如,在語句stmt1執行時,事務沒有提交更新,stmt1看到Reader1的值是2;當語句stmt2執行時,事務提交更新,stmt2看到Reader2的值是3;

二,使用行版本(Row Version)的隔離級別

在默認的隔離級別Read Commited下,在執行讀操做時,事務申請shared lock,讀寫操做相互阻塞。在隔離級別Read Uncommitted下,事務不會申請shared lock,所以讀操做不會阻塞寫操做,可是讀操做可能會讀到髒數據。髒數據是指被其它還沒有提交的事務修改以後的數據值,不是指更新以前的數據值。

行版本是指存儲在tempdb中,含有數據行和TSN的數據。數據表的一個Data Row,能夠有多個Row Version。修改操做發生時,SQL Server 建立一個Row Version,將Original Row複製到Row Version,並將當前事務的TSN也存儲在Row Version中。所以,Row Version存儲的是修改以前的數據值。

SQL Server 提供Snapshot隔離級別,用於讀取修改以前的數據值。在Snapshot隔離級別下,事務在修改任何數據以前,先將原始數據行復制到tempdb,建立數據行的一個原始版本(Row Version),注意,SQL Server只會複製被修改的數據行,對於未修改的數據行,不會保存行版本數據。後續其餘事務的讀操做都去讀該複製的行版本。在Snapshot隔離級別下,讀寫操做不會互相阻塞,使用行版本控制可以提升事務的併發性,可是有一個明顯的缺點,雖然用戶讀到的不是髒數據,可是數據可能正在被修改,很快就要過時。若是根據這個過時的數據作數據修改,可能會產生邏輯錯誤。

1,啓用Snapshot隔離級別

設置數據庫選項 ALLOW_SNAPSHOT_ISOLATION 爲 ON,沒有改變Session-Level的事務隔離級別,須要修改Session-Level的事務隔離級別爲SNAPSHOT,才能使用行版本數據

alter database current
set allow_snapshot_isolation on;

在使用Snapshot隔離級別時,必須將當前Session的隔離級別設置爲Snapshot,只有這樣,當前事務才能訪問Row Versioning的數據:

SET TRANSACTION ISOLATION LEVEL SNAPSHOT

2,數據庫選項READ_COMMITTED_SNAPSHOT(簡稱RCS)

在默認的隔離級別Read Committed下,使事務可以訪問Row Versioning數據,須要將數據庫選項READ_COMMITTED_SNAPSHOT設置爲ON:

alter database current
set allow_snapshot_isolation on;

alter database current 
set read_committed_snapshot on;

前提是必須設置數據庫選項ALLOW_SNAPSHOT_ISOLATION爲ON;一旦啓用RCS選項,在默認的Read Committed 隔離級別中,事務訪問版本化的數據行。在RCS隔離級別下,事務有兩個特性:

  • 事務使用行版本(Row version)代替加鎖,讀操做不會阻塞其餘事務的寫操做;
  • RCS隔離級別保證語句級別的事務一致性,查詢語句只能讀取在該語句執行時已經提交的數據,若是在該語句執行時數據更新還沒有提交,該語句讀取不到;

3,READ COMMITTED Snapshot隔離級別

在Read Committed 隔離級別下,事務不能讀取被其餘事務修改,但還沒有提交的數據,即只能讀取已提交更新的數據,READ COMMITTED隔離級別的行爲受到數據庫選項:READ_COMMITTED_SNAPSHOT的影響:

  • 若是設置RCS選項爲OFF(默認設置),數據庫引擎使用Shared Lock阻止其餘事務修改當前事務正在讀取的數據;當讀取被其餘事務修改,但還沒有提交更新的數據行時,該讀操做將被阻塞;
    • If READ_COMMITTED_SNAPSHOT is set to OFF (the default), the Database Engine uses shared locks to prevent other transactions from modifying rows while the current transaction is running a read operation. The shared locks also block the statement from reading rows modified by other transactions until the other transaction is completed.
  • 若是設置RCS選項爲ON,數據庫引擎使用行版本化(Row Versioning)的數據實現語句級別的一致性,不會阻塞其餘事務的寫操做,但只能讀取已提交更新的數據
    • If READ_COMMITTED_SNAPSHOT is set to ON, the Database Engine uses row versioning to present each statement with a transactionally consistent snapshot of the data as it existed at the start of the statement. Locks are not used to protect the data from updates by other transactions.

三,啓用快照隔離級別

1,使用snapshot 隔離級別

step1,設置數據庫選項

ALTER DATABASE CURRENT SET SINGLE_USER 
WITH ROLLBACK IMMEDIATE; ALTER DATABASE CURRENT SET ALLOW_SNAPSHOT_ISOLATION ON; --ALTER DATABASE CURRENT SET READ_COMMITTED_SNAPSHOT OFF; ALTER DATABASE CURRENT SET MULTI_USER;

step2,修改Session-Level的隔離級別爲snapshot

set transaction isolation level snapshot

2,使用Read_Committed_Snapshot隔離級別

ALTER DATABASE CURRENT SET SINGLE_USER 
WITH ROLLBACK IMMEDIATE; 
ALTER DATABASE CURRENT SET ALLOW_SNAPSHOT_ISOLATION ON; 
ALTER DATABASE CURRENT SET READ_COMMITTED_SNAPSHOT ON; 
ALTER DATABASE CURRENT SET MULTI_USER;

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

 

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

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

  • 當其餘事務未提交更新時,讀取行版本化的數據,即讀取修改以前的數據值;
  • 當其餘事務提交數據更新後,讀取修改後數據值;
  • 因爲該隔離級別不會申請共享鎖,所以不會阻塞其餘事務的更新操做;
  • 可以更新由其餘事務修改的數據;

五,Snapshot隔離級別(翻譯MSDN)

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

Specifies that data read by any statement in a transaction will be the transactionally consistent version of the data that existed at the start of the transaction. The transaction can only recognize data modifications that were committed before the start of the transaction. Data modifications made by other transactions after the start of the current transaction are not visible to statements executing in the current transaction. The effect is as if the statements in a transaction get a snapshot of the committed data as it existed at the start of the transaction.

1,在Snapshot隔離級別下,更新操做建立Row Version

一旦啓用Snapshot隔離級別,在事務中執行更新操做時,SQL Server將被更新的數據行的原始版本存儲在tempdb中,即在tempdb中保存數據行的Original data,所以,讀取行版本的數據,都只能讀取到數據行被更新以前的值。每個事務都擁有一個惟一的,遞增的順序號,記做TSN(Transaction Sequence Number),TSN可以惟一標識一個事務,每個行版本都存儲一個TSN,標識建立該行版本的事務。

Once snapshot isolation is enabled, updated row versions for each transaction are maintained in tempdb. A unique transaction sequence number identifies each transaction, and these unique numbers are recorded for each row version.

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

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

The term "snapshot" reflects the fact that all queries in the transaction see the same version, or snapshot, of the database, based on the state of the database at the moment in time when the transaction begins. No locks are acquired on the underlying data rows or data pages in a snapshot transaction, which permits other transactions to execute without being blocked by a prior uncompleted transaction. Transactions that modify data do not block transactions that read data, and transactions that read data do not block transactions that write data, as they normally would under the default READ COMMITTED isolation level in SQL Server. This non-blocking behavior also significantly reduces the likelihood of deadlocks for complex transactions.

3,Snapshot 使用樂觀併發模式

Snapshot隔離級別使用樂觀併發模式,若是一個Snapshot 事務嘗試去提交數據行的更新,可是該數據行已經被其餘事務修改,而且修改的時間早於當前事務開始的時間,那麼SQL Server將當前事務做爲失敗者,並回滾其事務操做。樂觀併發模式用於衝突較少的環境中,若是Application在更新數據時常常發生衝突,Snapshot隔離級別可能不是最好的選擇。

Snapshot isolation uses an optimistic concurrency model. If a snapshot transaction attempts to commit modifications to data that has changed since the transaction began, the transaction will roll back and an error will be raised. 

4,Snapshot 隔離和 Row Version的工做模式

當啓用Snapshot隔離級別時,每個更新數據的操做都會在tempdb中存儲該行的原始副本,術語叫做行版本(RowVersion),SQL Server爲每一個行版本添加事務的TSN,該TSN可以惟一標識更新操做所在的事務。讀操做在讀數據時,按照如下順序進行:

  • 建立一個新的事務,爲其分配TSN,一個惟一,遞增的序號;
  • snapshot事務從數據表中讀取數據行,從tempdb中讀取行版本(row version),該行版本的TSN最接近當前事務的TSN,但比當前事務的TSN小;
  • 在建立Snapshot時,從已提交的事務中獲取行版本數據,若是行版本數據標識的事務還沒有提交,那麼從更早的事務中獲取已提交更新的數據;
  • 事務從tempdb中讀取行版本數據,事務不會看到新插入的數據,由於插入數據的TSN比當前事務的TSN大;
  • 事務可以看到被其餘事務刪除的數據,前提是刪除數據的事務的TSN比當前事務的TSN大,這是由於其餘事務將行版本保存到tempdb中,當前事務從tempdb中讀取行版本數據;

When the SNAPSHOT isolation level is enabled, each time a row is updated, the SQL Server Database Engine stores a copy of the original row in tempdb, and adds a transaction sequence number to the row. The following is the sequence of events that occurs:

  • A new transaction is initiated, and it is assigned a transaction sequence number.

  • The Database Engine reads a row within the transaction and retrieves the row version from tempdb whose sequence number is closest to, and lower than, the transaction sequence number.

  • The Database Engine checks to see if the transaction sequence number is not in the list of transaction sequence numbers of the uncommitted transactions active when the snapshot transaction started.

  • The transaction reads the version of the row from tempdb that was current as of the start of the transaction. It will not see new rows inserted after the transaction was started because those sequence number values will be higher than the value of the transaction sequence number.

  • The current transaction will see rows that were deleted after the transaction began, because there will be a row version in tempdb with a lower sequence number value.

The net effect of snapshot isolation is that the transaction sees all of the data as it existed at the start of the transaction, without holding or placing any locks on the underlying tables. This can result in performance improvements in situations where there is contention.

A snapshot transaction always uses optimistic concurrency control, with holding any locks that would prevent other transactions from updating rows. If a snapshot transaction attempts to commit an update to a row that was changed after the transaction began, the transaction is rolled back, and an error is raised.

 

參考文檔:

Snapshot Isolation in SQL Server

Isolation Levels in the Database Engine

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

相關文章
相關標籤/搜索