------------------------------------------------------------------------數據庫
-- Author : happyflystone併發
-- Date : 2009-10-26app
-- Version: Microsoft SQL Server 2005 - 9.00.2047.00 (Intel X86)性能
-- Apr 14 2006 01:12:25學習
-- Copyright (c) 1988-2005 Microsoft Corporationui
-- Enterprise Edition on Windows NT 5.2 (Build 3790: Service Pack 2)spa
-- 轉載請註明出處,更多請關注:http://blog.csdn.net/happyflystone.net
-- 關鍵字:行版本控制器 RCSI SI 鎖定提示 鎖超時設定線程
------------------------------------------------------------------------版本控制
在前面一篇我說了鎖的行鎖與頁鎖之間的是與非,鎖升級、動態鎖、死鎖,加上第六篇的一些理論加實例,基本上鎖的相關知識這一個階段結束了,這一篇咱們來學習一下2005的新特性行版本控制器,順便說說鎖定提示及鎖超時設定,其實這個鎖定提示在前面已經常常說起了,只是咱們沒有細說。
10、行版本控制綜述
行版本控制是SQLSERVER2005保證數據完整及一致的新機制。咱們前面提到併發模型有兩種:悲觀與樂觀併發,而行版本控制是樂觀併發下的一種保障數據完整及一致的新技術。行版本控制和前面說起的鎖定機制不大同樣,它保障了寫的進程與讀的進程間不會阻塞,而且在保證不讀到未提交的數據下又提高了數據庫的併發能力,然而咱們要注意的是樂觀併發下寫的進程仍是會獲取排它鎖定,上面說起的一些鎖定模式、鎖定時間及管理死鎖的方式都適用於它。
SQLSERVER2005使用行版本控制的隔離有兩個:RCSI 和 SI。RCSI是相對無阻塞的已提交讀模式,所謂相對無阻塞是相對於傳統的已提交讀模式,在這種模式下寫進程不會阻塞讀進程,讀進程不會設置共享鎖定,而是使用行版本控制讀取語句級的一致性的數據,簡單的說就是任何讀均可以獲得語句開始那一時刻最近的已經提交數據。快照隔離(SI)可使任何讀進程讀取到交易級的一致性數據,簡單的說就是任何讀進程均可以讀取到交易開始時已提交數據。
SQLSERVER2005如何作到寫不阻塞讀的呢?一旦啓用RCSI或SI後數據庫開始在tempdb中存儲全部已經修改過的記錄副本(記錄版本,之後咱們直接稱行版本),同時保證在只要有進程須要這些數據就會一直維持這些行版本,因此tempdb又被咱們稱爲版本存儲區。很顯然的是啓用行版本控制後tempdb得須要更多的空間來管理行版本,因此若是你的數據庫使用了行版本管理,必定要管理好tempdb。行版本如何存儲在版本存儲區我下面再說。
好,總體上來講咱們應該有這樣一個概念:已經提交的數據存儲在當前數據庫,而當數據修改前的數據被複制到tempdb中,那麼它們之間如何聯繫呢?這兒咱們引入另外一個術語:XSN,注意哦,區別於LSN哦。XSN稱爲事務序列號,新行經過這個XSN和tempdb裏的行版本之間保持聯繫,是否是有點指針味道呀,哈哈,同時咱們要注意了,新行XSN指向行版本區的某一舊行,同時這一舊行可能包含指向列舊的數據行XSN,SQLSERVE經過這個鏈表能夠訪問到正確的版本。
說了這麼多,感情這個行版本管理後好處多多呀,至少加強了併發能力吧,但是在更改當前數據庫使用行版本管理前仍是要三思而行:首先,增長了tempdb的負擔,這種負擔不只僅是空間上的。接着,維護舊版的數據行必然會下降更新操做的能力,無論有沒有讀進程存在,只要有更新存在數據庫就得爲此付出代價。第三,增長的併發能力使得每個讀進程都得付出額外的開銷來訪問剛纔咱們提到的XSN鏈表找到合適行版本。最後咱們說阻塞是不能徹底避免的,就是在這種樂觀模式下寫寫仍是阻塞的。在後續咱們模擬在SI下的更新衝突。
有人要問了RCSI和SI之間有什麼差異呢?其實RCSI和SI行爲上基本相似的,都是能夠在當前數據鎖定的前提下讀取到當前數據已經提交的早期版本,它們的主要差異有二:一,行版本記錄在行版本區保存的時效。此話怎麼理解呢,我在前面說到RCSI是語句級的而SI是事務級的,這就是直接致使數據行版有多久的關鍵。二,RCSI是已經提交讀的無阻塞的變種,而SI是存在阻塞的。下面咱們會說道說道這兩種行爲。
11、行版本區
SQLSERVER2005只要開啓快照,全部更新和刪除就會生成已經提交的行版本,而這些行版本是保存在行版本區,即tempdb數據庫的數據分頁上,隨時保障快照的查詢須要,換句話說只要有查詢須要,行版本區數據就存在。SQLSERVER2005有一個清理線程,常規好像是一分鐘就進行一次回收,對於SI隔離下的查詢行版本保存到事務結束(這就是爲何在SI隔離下不會出現 不可重複讀,由於在SI模式下整個事務都取的是事務開始那一刻的行版本數據),對於RCSI隔離下的查詢行版本一直保存到當前查詢語句結束(這就是爲何RCSI隔離下會出現 不可重複讀,由於在RCSI模式下整個事務都取的是表裏面最近一次提交的數據,例如事務A有兩次查詢,但在兩次查詢間數據被另外一個事務B修改並提交了,那麼事務A的兩次查詢的結果就會不同,形成不可重複讀)。
這兒提到tempdb,得稍微提提這個tempdb,tempdb也是記錄日誌的,並非好多人認爲的不記錄,它的日誌是爲了臨時對象上的事務回滾,記住只能回滾,不能恢復或重作,固然是是題外話,一帶而過。
Tempdb中有三種類型的對象:用戶對象、內部對象、版本庫。這個版本庫的數據來源有三:一,重建索引或有快照級別的數據庫上執行了DML(咱們一會說這兩個快照級別);二,觸發器,這有別於2000哦,2005的僞表(deleted 、inserted)是由行版本產生的;三,活動結果集。
12、已經提交讀快照隔離下讀寫行爲
RCSI咱們必定要記住它是一個語句級的快照隔離級別,任何查詢均可以查詢到語句開始時最近的已經提交的數據。
如何開啓這個級別隔離咱們前面已經寫過了,對,用alter database dbname set read_comm.itted_snapshot on 就行,在運行這一命令要注意時不能用戶在鏈接數據庫,若是有人在使用數據庫這個命令就會阻塞。這個命令有兩個開關項:with nowait 和rollback來避免阻塞和終止任何數據庫鏈接,你們能夠查查聯機從書。
我在前面寫隔離級別的事例時提到這個隔離級別和用鎖定的已提交讀具備同樣的行爲,下面咱們用一個實例來看看:
先修改當前當前庫的READ_COMMITTED_SNAPSHOT爲ON
ALTER DATABASE TESTCSDN SET READ_COMMITTED_SNAPSHOT ON GO Exec sp_us_lockinfo Go
--test data and table create table ta(id int,col varchar(10)) insert ta select 1 ,'a' union all select 2,'b' union all select 3,'c' go
查詢一:
begin tran update ta set col = 'd' where id = 1 waitfor delay '00:00:05' –故意加延時看看這個鎖定是否影響查詢二 exec sP_us_lockinfo –查看當前鎖定狀況,由圖咱們知道在表上有排它鎖定 commit
查詢二:
begin tran waitfor delay '00:00:01'—確保表上已經有排它鎖定 select * from ta where id = 1 -–行版本讀到最近提交的數據 /* id col ----------- ---------- 1 a (1 行受影響) */ waitfor delay '00:00:05'—-保證查詢一已經提交數據 select * from ta where id = 1 – 查詢到最新行版本數據 /* id col ----------- ---------- 1 d (1 行受影響) */ commit
回顧一下以上過程,咱們發現這個已提交快照和已提交鎖定方式同樣的行爲,可是它比鎖定模式有更強的併發能力 ,由於讀寫進程間再也不阻塞。另外咱們注意到沒有,不須要在每個會話中使用SET來設置選項就可使用RCSI,也就是咱們無需對應用程序做任何修改就能夠從缺省的鎖定方式的已提交讀切換到快照方式的已提交讀,從而下降阻塞帶來的併發衝突。
13、快照隔離下的讀寫行爲
SI是SQLSERVER2005引入的一個新的隔離,要啓用必須在兩個地方同時啓用:一、啓用Allow_SNAPSHOW_ISOLATION;二、在會話中使用SET TRANSACTION ISOLATION LEVEL命令爲每個會話設置隔離。咱們在前面說過它是一個樂觀模式的隔離,相似於已提交讀快照隔離,可是又有些差異。
啓用命令:
ALTER DATABASE DB_NAME SET ALLOW_SNAPSHOT_ISOLATION ON;
當咱們使用這個命令時,若是有活動鏈接時它不會像RCSI阻塞,可是若是有活動事務時仍是會被阻塞。這個命令運行後數據的狀態不會當即成ON狀態 ,而是經歷一個IN_TRANSITION_TO_ON的狀態,這時數據庫處於等待數據庫中全部事務結束並開始爲更新和刪除產生版本數據,一旦在alter命令開始時已經進行的事務一結束,數據庫就會進入ON狀態。同理我修改成OFF時數據的庫狀態也會經歷一箇中間狀態IN_TRANSITION_TO_OFF,等待活動的事務結束。一旦全部的活動事務結束數據庫就會變爲OFF狀態。好下面咱們來模擬啓動過程,關閉的過程你們本身模擬吧。
咱們模擬打開的過程:
查詢一:開始一個事務,記住不要提交可回滾
BEGIN TRAN UPDATE TA SET COL = 'B' WHERE ID = 1
查詢二:開啓快照
ALTER DATABASE DBlock SET ALLOW_SNAPSHOT_ISOLATION on;
查詢三:
exec sp_us_lockinfo --你們能夠看到當前數據處於中間態:IN_TRANSITION_TO_ON
--咱們模擬這時開啓SI進行數據訪問,看看會是什麼結果 SET TRANSACTION ISOLATION LEVEL SNAPSHOT BEGIN TRAN SELECT * FROM TA WHERE ID = 1 /* id col ----------- ---------- 消息3956,級別16,狀態1,第4 行 快照隔離事務未能在數據庫'dblock' 中啓動,由於用於啓用此數據庫的快照隔離的 ALTER DATABASE 命令還沒有完成。數據庫正在轉換到掛起ON 狀態。您必須等待, 直到ALTER DATABASE 命令成功完成。 */
接着,咱們在查詢一里 增長一句:COMMIT;而後咱們再運行查詢三:
那好,咱們經過上面的命令已經學會使用這個隔離級別。SI保證事務級的數據一致性,任何讀操做均可以獲得事務開始時最近已經提交的數據版本。下面咱們再模擬一下查詢快照數據:
查詢一:
SELECT * FROM TA /* id col ----------- ---------- 1 B (1 行受影響) */ BEGIN TRAN UPDATE TA SET COL = 'C' WHERE ID = 1 WAITFOR DELAY '00:00:05' exec sp_us_lockinfo /*
*/ COMMIT
查詢二:
SET TRANSACTION ISOLATION LEVEL SNAPSHOT BEGIN TRAN SELECT * FROM TA WHERE ID = 1 /* id col ----------- ---------- 1 B (1 行受影響) */ waitfor delay '00:00:05' SELECT * FROM TA WHERE ID = 1 /* id col ----------- ---------- 1 B (1 行受影響) */ commit tran SELECT * FROM TA WHERE ID = 1 /* id col ----------- ---------- 1 C (1 行受影響) */
還記得我在前面說過SI是有衝突阻塞(錯誤:3960)的哦, 下面咱們模擬一下,這也是在提醒你們使用SI模式時必定要潛在的阻塞,好看下面的實例:
查詢一:
SET TRANSACTION ISOLATION LEVEL SNAPSHOT BEGIN TRAN SELECT * FROM TA where id = 1 WAITFOR DELAY '00:00:05' UPDATE TA SET COL = 'c' WHERE ID = 1 /* 消息3960,級別16,狀態2,第9 行 快照隔離事務因爲更新衝突而停止。您沒法在數據庫'dblock'中使用快照隔離來直接 或間接訪問表'dbo.TA',以便更新、刪除或插入已由其餘事務修改或刪除的行。請重 試該事務或更改update/delete 語句的隔離級別。 */
查詢二:
WAITFOR DELAY '00:00:02' BEGIN TRAN UPDATE TA SET COL = 'd' WHERE ID = 1 commit tran SELECT * FROM TA WHERE ID = 1 /* id col ----------- ---------- 1 d (1 行受影響) */
13、鎖定提示(LOCK HINTS)
隔離級別是會話級別的,在會話內內對持有鎖、阻塞 、鎖的生命週期產生影響。然而,必要時咱們使用表級鎖定提示來改變這種默認鎖定行爲,可是咱們必定要注意這種操做不當會影響併發性能。
咱們必定要記住使用鎖定提示是表級提示,由於咱們通常是在From子句中使用wth指定。另外SQLSERVER2005推薦使用With(Locktype),不帶with語法儘可能不要使用。
下面枚舉一下鎖定提示的關鍵字(申明太晚了,我直接複製了之前收藏的):
鎖提示使用示例:
SELECT au_lname FROM authors WITH (NOLOCK) 鎖定提示 描述 HOLDLOCK 將共享鎖保留到事務完成,而不是在相應的表、行或數據頁再也不須要 時就當即釋放鎖。它等同於SERIALIZABLE,只不過僅做用於表級。 NOLOCK 不發出共享鎖,而且不要提供排它鎖。當此選項生效時,可能會讀取未提交的事務或一組在讀取中間回滾的頁面。有可能發生髒讀。僅應用於 SELECT語句,顯然至關於未提交讀級別。 PAGLOCK 在一般使用單個表鎖的地方採用頁鎖。 READCOMMITTED 用與運行在提交讀隔離級別的事務相同的鎖語義執行掃描。默認狀況 下,SQL Server 2000 在此隔離級別上操做。 READPAST 跳過鎖定行。此選項致使事務跳過由其它事務鎖定的行(這些行日常 會顯示在結果集內),而不是阻塞該事務,使其等待其它事務釋放在這 些行上的鎖。READPAST鎖提示僅適用於運行在提交讀隔離級別的事 務,而且只在行級鎖以後讀取。僅適用於SELECT語句。 READUNCOMMITTED 等同於NOLOCK。 REPEATABLEREAD 用與運行在可重複讀隔離級別的事務相同的鎖語義執行掃描。 ROWLOCK 使用行級鎖,而不使用粒度更粗的頁級鎖和表級鎖。 SERIALIZABLE 用與運行在可串行讀隔離級別的事務相同的鎖語義執行掃描。 等同於HOLDLOCK。 TABLOCK 使用表鎖代替粒度更細的行級鎖或頁級鎖。在語句結束前,SQL Server 一直持有該鎖。可是,若是同時指定 HOLDLOCK,那麼在事務結束以前,鎖將被一直持有。 TABLOCKX 使用表的排它鎖。該鎖能夠防止其它事務讀取或更新表,並在語句或事務結束前一直持有。它和TABLOCKG與XLOCK連用的效果同樣。 UPDLOCK 讀取表時使用更新鎖,而不使用共享鎖,並將鎖一直保留到語句或事務的結束。UPDLOCK的優勢是容許您讀取數據(不阻塞其它事務)並在之後更新數據,同時確保自從上次讀取數據後數據沒有被更改。消除轉換類型的死鎖重要技術。 XLOCK 提示SQLSERVER在語句使用的所有數據上使用排它鎖,並一直保持到 事務結束時。可使用 PAGLOCK或TABLOCK指定該鎖,這種狀況下 排它鎖適用於適當級別的粒度
14、鎖定超時
SET LOCK_TIMEOUT n;
暈,這個看聯機從書就好了,不能再寫了。