設置SQLServer的行版本控制隔離級別


1.--查詢數據庫狀態
select name,user_access,user_access_desc,snapshot_isolation_state,snapshot_isolation_state_desc,is_read_committed_snapshot_on from sys.databases

2. 查看當前數據庫的隔離級別

  DBCC Useroptions -- isolation level 這項的值就代表當前的隔離級別

2。 更改數據庫與樂觀鎖有關的參數 (必須關閉除了當前連接之外的所有的數據庫連接 )

ALTER DATABASE [dbname] SET SINGLE_USER WITH ROLLBACK IMMEDIATE ;
ALTER DATABASE [dbname] SET ALLOW_SNAPSHOT_ISOLATION ON
ALTER DATABASE [dbname] SET READ_COMMITTED_SNAPSHOT ON;
ALTER DATABASE [dbname] SET MULTI_USER;

2005支持5種隔離級別來控制讀操作的行為,分別是:

  • Uncommitted Read
  • Read Committed
  • Repeatable Read
  • Snapshot
  • Serializable

其中三種是悲觀模式下使用,一種(Snapshot)是樂觀模式下使用還有一種(Read Committed)倆種模式下都可用.

修改隔離級別的語句如下,只能修改一個鏈接的隔離級別,不能修改全局的默認隔離級別

SET TRANSACTION ISOLATION LEVEL    { READ UNCOMMITTED     | READ COMMITTED     | REPEATABLE READ     | SNAPSHOT     | SERIALIZABLE     } [ ; ]

通過如下命令設置樂觀模式的改隔離級別:

1. ALTER DATABASE [dbname] SET ALLOW_SNAPSHOT_ISOLATION ON

2. set transaction isolation level snapshot

假如我們不執行step1,只執行step2,然后開啟事務進行查詢,會報如下錯誤:

Msg 3952, Level 16, State 1, Line 3
Snapshot isolation transaction failed accessing database 'AdventureWorks' because snapshot isolation is not allowed in this database. Use ALTER DATABASE to allow snapshot isolation.

 

ALTER DATABASE [dbname] SET READ_COMMITTED_SNAPSHOT ON;

set transaction isolation level Read Committed

--由於SQL Server默認的isolation level 就是Read Committed,所以這句可以不需要,這就意味着當設置了數據庫參數READ_COMMITTED_SNAPSHOT后,

隔離級別就自動變成了read committed snapshot.

兩種行版本控制隔離級別的差別:

READ_COMMITTED_SNAPSHOT  數據庫選項為ON時, READ_COMMITTED事務通過使用行版本控制提供語句級讀取一致性.同時在執行DML語句的時候,會把snapshot數據自動存儲在tempdb里面,哪怕當前session的隔離級別不是READ_COMMITTED.因為每個session的隔離級別是可以隨時變的,所以只要數據庫的這個選項設置為on的時候,就必須存儲行版本數據,以提供行版本數據控制。


ALLOW_SNAPSHOT_ISOLATION 數據庫選項為ON時,SNAPSHOT事務通過使用行版本控制提供事務級讀取一致性在執行DML的時候,會保持更多的行版本數據,以供需要行版本數據的snapshot隔離級別使用。所以這個可能會影響tempdb的使用。

 

行版本數據是在被更新的時候(DML),把前snapshot數據放到tempdb里面,可以在視圖sys.dm_tran_version_store查到對於的記錄.

select * from sys.dm_tran_version_store

 

 下面是一些實驗例子

--認清SQL_Server的基於行版本控制的兩種隔離級別
--快照隔離級別(snapshot)和已提交讀快照隔離級別(read committed snapshot)

--特點:在這兩種隔離級別下,讀取數據時不再請求共享鎖,而且永遠不會與修改進程的數據發生沖突,如果請求的行被鎖定(例如正在被更新),
--SQL_Server會從行版本存儲區返回最早的關於該行的記錄
--說明:首先這兩種隔離級別都是基於快照的實現模式,所以使用前必須修改數據庫選項"允許快照隔離"為ON,否則
-- 以下兩種隔離級別將都被禁用: ALTER DATABASE DBNAME SET ALLOW_SNAPSHOT_ISOLATION ON -- 修改這個選項時可能會需要將數據庫置為單用戶模式 ALTER DATABASE DBNAME SET SINGLE_USER WITH ROLLBACK IMMEDIATE -- 修改完允許快照隔離后再將數據庫重置為多用戶模式 ALTER DATABASE DBNAME set MULTI_USER -- 一、快照隔離級別是一種全新的隔離級別,在打開“允許快照隔離”選項后,不管是否使用快照隔離級別-- 在更新數據時,SQL SERVER總是會在tempdb庫中保存更改前的最后的行數據鏈接列表,從這里可以想到 -- 將會影響SQL SERVER在更新數據時的事務性能。當然,該隔離級別的主要作用是提高並發,所以讀取多,修改少的時候可大膽使用. SET TRANSACTION ISOLATION LEVEL SNAPSHOT -- 二、已提交讀快照隔離級別,其實就是SQL Server默認隔離級別Read Committed的衍生品,或者說是 -- 另一種版本的已提交讀,打開此數據庫選項的命令是: ALTER DATABASE DBNAME SET read_committed_snapshot ON -- 在這里大家要明白,它只是一個數據庫選項開關,是在 READ COMMITTED 隔離模式下時才會起作用,而且 -- 將改變整個數據庫的全局行為。因為SQL SERVER默認就是在READ COMMITTED隔離模式下,所以在稍后的 -- 示例中我們不會用到SET TRANSACTION ISOLATION LEVEL READ COMMITTED語句,但是我們心里要明白。 --適用情況:主要是讀取數據的環境,在這種環境下偶爾需要修改操作並且很少發生更新沖突。 --區別:我們會在稍后的演示中進行說明,那樣更容易理解一些。 --示例一:快照 --創建環境: IF DB_ID('DB_TEST') IS NOT NULL DROP DATABASE DB_TEST; GO CREATE DATABASE DB_TEST USE DB_TEST; GO IF OBJECT_ID('T_TEST','U') IS NOT NULL DROP TABLE T_TEST GO CREATE TABLE T_TEST(ID INT IDENTITY(1,1),COL VARCHAR(50)) GO INSERT INTO T_TEST SELECT 'AAAAAAAAA' UNION ALL SELECT 'BBBBBBBBBB' GO SELECT * FROM T_TEST /* ID COL 1 AAAAAAAAA 2 BBBBBBBBBB */ -- 在連接1中執行如下語句(確保ALLOW_SNAPSHOT_ISOLATION已置為ON) USE DB_TEST; GO ALTER DATABASE DB_TEST SET ALLOW_SNAPSHOT_ISOLATION ON; GO BEGIN TRAN SELECT COL FROM T_TEST WHERE ID=2; UPDATE T_TEST SET COL='CCCCCCC' WHERE ID=2; SELECT COL FROM T_TEST WHERE ID=2; -- 通過輸出的結果我們可以看到,在未完成的事務中ID=2的COL值從'B'變為'C',而且你應該注意到我這里沒有使用快照隔離級別,還是用的SQL SERVER默認隔離級別,-- 但是因為我們打開了ALLOW_SNAPSHOT_ISOLATION選項,這個時候,我們的事務應該在更改ID=2的COL值之前就把之前的行狀態存儲到了tempdb中,
-- 那么我們怎么才能證明
這個猜測呢,動態視圖sys.dm_tran_version_store可以幫助我們,執行: SELECT * FROM sys.dm_tran_version_store -- 你一定可以看到在版本存儲區中已經有了一行數據了,接下來我們再打開一個連接2,執行如下SQL: USE DB_TEST GO --SET TRANSACTION ISOLATION LEVEL SNAPSHOT; --這里我們先注釋掉設置隔離級別為快照模式 BEGIN TRAN SELECT COL FROM T_TEST WHERE ID=2; -- 可以看到查詢一直在等待,是因為我們在連接1中一直保持着該行的排它鎖X。但是現在我們把該事務commit或rollback -- 掉,然后把快照隔離模式的注釋打開,重新執行上面的語句,我們就可以看到 /* BBBBBBBBBB */ -- 我們可以想象到SQL SERVER在這種隔離級別下的查找思路,它會先去原表查找該行數據,待發現該行被鎖后,則去 -- tempdb數據庫存儲的行版本列表中取出最近的一次數據,這樣就避免了等待,但是前提是要求數據查詢不用那么精確 -- 的情況下,當然,你是否在這里忽略了一個問題,即:SQL SERVER僅會在修改該行數據前才會去存儲最新的行版本, -- 而在修改的事務結束后,SQL SERVER並不會去更新之前的快照到最新的行版本,但是即使這樣我們也不用擔心,因為 -- 這個時候原表的該行數據已經不是鎖定狀態,其他之后的查詢依然會得到最新的數據。唯一注意的一點,我們還是用 -- 代碼說明:在連接1中用COMMIT TRAN 提交事務,然后繼續執行連接2中的查詢: SELECT COL FROM T_TEST WHERE ID=2; -- 我們發現數據還是之前的數據BBBBBBB,為什么?因為事務隔離級別!在事務中的任何地方讀取該行數據時,它獲取的 -- 總是在事務開始時獲取的數據,這里要牢記,因為他是稍后我們要說的已提交讀快照隔離級別的第一個不同點。 -- 接下來我們說說快照隔離級別的另一個特點:沖突檢測,代碼說明,簡潔易懂: -- 在連接1中執行如下語句: USE DB_TEST; GO SET TRANSACTION ISOLATION LEVEL SNAPSHOT;--注意這里我們要設置隔離級別為快照模式 BEGIN TRAN SELECT COL FROM T_TEST WHERE ID=2; -- 這里我們可以得到一個數據,然后再打開一個連接2,執行如下SQL: USE DB_TEST; GO UPDATE T_TEST SET COL='DDDDDDD' WHERE ID=2; -- 回到連接1,繼續執行SQL: UPDATE T_TEST SET COL='EEEEEEE' WHERE ID=2; -- 這時SQL SERVER 就會檢測到你在連接1中事務開始時讀取的數據已經與現在的數據發生了改變,所以就會報出更新 -- 沖突的錯誤: /* 消息 3960,級別 16,狀態 4,第 1 行 快照隔離事務由於更新沖突而中止。您無法在數據庫'DB_Test'中使用快照隔離來直接或間接訪問表 'dbo.T_TEST', 以便更新、刪除或插入已由其他事務修改或刪除的行。請重試該事務或更改 update/delete 語句的隔離級別。 */ -- 這里,其實就是快照隔離級別和已提交讀快照隔離級別的第二大區別了,READ COMMITTED SNAPSHOT不會檢測更新沖突 --示例二:已提交讀快照 -- 在連接1中執行如下語句: ALTER DATABASE DB_TEST SET READ_COMMITTED_SNAPSHOT ON;--首先我們打開該數據庫選項 USE DB_TEST; GO; BEGIN TRAN UPDATE T_TEST SET COL='FFFFFFF' WHERE ID=2; SELECT COL FROM T_TEST WHERE ID=2; -- 在該事務里,你將得到你剛剛更新過的值FFFFFFFF -- 在連接2中執行如下語句: USE DB_TEST; GO BEGIN TRAN SELECT COL FROM T_TEST WHERE ID=2; -- 這里你將得到連接1中的事務在修改數據之前的值,而非FFFFFF,這是肯定的。 -- 這時我們提交連接1中的事務: COMMIT TRAN; -- 在連接2中再進行查詢時,我們驚奇的發現與在快照中不同的是,我們竟然在未完成的事務2中得到了連接1中的事務 -- 更改后的值!這也是為什么不會進行更新沖突檢測的原因,不如我們測試一下: -- 將之前連接1中的事務提交或回滾,然后執行如下SQL: USE DB_TEST; GO SET TRANSACTION ISOLATION LEVEL READ COMMITTED;--這里我們顯示指定隔離級別是因為剛才指定的快照隔離 -- 級別會在沒有關閉的會話中一直有效。 BEGIN TRAN SELECT COL FROM T_TEST WHERE ID=2; --之后,我們再把連接2中的事務提交或回滾掉,執行如下SQL: SET TRANSACTION ISOLATION LEVEL READ COMMITTED; UPDATE T_TEST SET COL='aaaaa' WHERE ID=2; SELECT COL FROM T_TEST WHERE ID=2; -- 好了,這個時候我們再在連接1中更新這條在事務1中讀取后但是在外部被更新過的數據: UPDATE T_TEST SET COL='測試已提交讀更新沖突檢測' WHERE ID=2; -- 我們發現更新可以正常進行,最后我們關閉所有連接,並更改數據庫選項: ALTER DATABASE DB_TEST SET ALLOW_SNAPSHOT_ISOLATION OFF; ALTER DATABASE DB_TEST SET READ_COMMITTED_SNAPSHOT OFF; --總結:快照隔離模式是樂觀並發模型,可以避免臟讀、丟失更新、不可重復讀、幻讀、而且有更新沖突檢測的特點。 --已提交快照讀隔離模式和已提交讀模式是相同的,都只能避免臟讀,都無更新沖突檢測,但是不同的是,已提交讀快照隔離級別是樂觀並發模型,並且讀取數據不會發生等待 --另附所有隔離級別的允許或防止的問題等。 ============================================================================================== 隔離級別 臟讀 丟失更新 不可重復讀 幻讀 並發模型 更新沖突檢測 ---------------------------------------------------------------------------------------------- 未提交讀 是 是 是 是 悲觀 否 ---------------------------------------------------------------------------------------------- 已提交讀   否 是 是 是 悲觀 否 ---------------------------------------------------------------------------------------------- 可重復讀 否 否 否 是 悲觀 否 ---------------------------------------------------------------------------------------------- 可串行讀 否 否 否 否 悲觀 否 ---------------------------------------------------------------------------------------------- 快照 否 否 否 否 樂觀 是 ---------------------------------------------------------------------------------------------- 已提交讀快照 否 是 是 是 樂觀 否 ==============================================================================================

DDL Statements That Are Not Allowed Within Snapshot Isolation

The following statements are not allowed within a transaction that is running under snapshot isolation because of their disruptive potential on the snapshot copies of the data:

  • CREATE INDEX
  • CREATE XML INDEX
  • ALTER INDEX
  • ALTER TABLE
  • DBCC DBREINDEX
  • ALTER PARTITION FUNCTION
  • ALTER PARTITION SCHEME
  • DROP INDEX
  • Common language runtime (CLR) DDL

An attempt to run one of these statements will cause a severity level 16 message to be returned, such as:

Msg 3964, Level 16, State 1, Line 1
Transaction failed because this DDL statement is not allowed
inside asnapshot isolation transaction. Since metadata is not
versioned,a metadata change can lead to inconsistency 
if mixed within snapshot isolation.

refer:
SQL Server 2005 Row Versioning-Based Transaction Isolation http://msdn.microsoft.com/en-us/library/ms345124%28SQL.90%29.aspx
Using Row Versioning-based Isolation Levels http://msdn.microsoft.com/en-us/library/ms189050.aspx


免責聲明!

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



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