大家好,歡迎回到性能調優培訓。上個星期我通過討論悲觀並發模式拉開了第5個月培訓的序幕。今天我們繼續,討論下樂觀並發模式(Optimistic Concurrency)。
行版本(Row Versioning)
樂觀並發模式自SQL Server 2005后引入,並基於行版本控制(Row Versioning)原則。行版本控制背后的想法是讀操作(SELECT查詢)不再需要獲得共享鎖(Shared Lock)。不去等待直到成功獲得共享鎖(Shared Lock),讀操作是返回行前一個提交的版本。老的,前一個版本被存儲在所謂的版本存儲(Version Store)里,這個在TempDb里永駐。寫操作(UPDATE,DELETE語句)明確復制老版本到版本存儲,新版本中含一個指針指向versionstore里面舊行。下圖詮釋了這個概念。
增加這個指針的一個副作用是每個記錄會增加額外的14 bytes。這會帶來:
- 堆表上的轉發記錄(Forwarding Records)
- 聚集表上的頁分裂(Page Splits)
另外,你也要按需計划和大小TempDb,因為你會引入額外的I/O,在默認配置下會帶來競爭問題。現在讓我們看看SQL Server提供給你的2個新的樂觀隔離級別(optimistic isolation levels)。
樂觀隔離級別(Optimistic Isolation Levels)
自SQL Server 2005起,關系引擎提供2個新的樂觀隔離級別,它們是基於上一部分討論過的行版本控制概念。
- 讀提交快照隔離(Read Committed Snapshot Isolation (RCSI))
- 快照隔離(Snapshot Isolation (SI))
我們來詳細看下這2個隔離級別。RCSI提供你基於快照語句級別的隔離。換句話說,SQL Server總會返回你在語句開始前有效的版本。它是提交讀隔離級別(Read Committed Isolation Level)的樂觀實現。因此使用這個隔離級別你會有不可重復讀(Non-Repeatable Reads)。
1 ALTER DATABASE AdventureWorks2012 SET READ_COMMITTED_SNAPSHOT ON 2 GO 3 4 -- Check if RCSI is now enabled 5 SELECT name,is_read_committed_snapshot_on 6 FROM sys.databases 7 WHERE database_id = DB_ID('AdventureWorks2012') 8 GO
RCSI的一個好處是對數據庫/應用程序本身它是完全透明的:你重要在數據庫上啟用它,然后對於每個查詢新的默認隔離級別是讀提交快照隔離(Read Committed Snapshot Isolation)。因此通過對指定數據庫啟用RCSI,你可以克服鎖和阻塞問題,即使死鎖問題也很容易。下面代碼顯示了對於給出的數據庫如何啟用RCSI:
對於你SELECT查詢,如果你想有重復讀(Repeatable Reads)的樂觀方式,你可以使用快照隔離(Snapshot Isolation (SI))隔離級別。快照隔離提供你開箱即用(out of box)的重復讀,這就是說你總拿到在你事務開始前有效的行版本。遺憾的是快照隔離並不完全透明:
- 快照隔離級別必須通過會話明確請求。因此在你的程序里你需要修改代碼。
- 你的查詢會執行如所謂的更新沖突(Update Conflicts),SQL Server會回滾事務。因此在你的程序里你需要相應的進行處理這個情況。
下面代碼向你展示了對於指定的數據庫,如何啟用快照隔離(Snapshot Isolation),如何請求這個新的隔離級別。
1 -- Enable Snapshot Isolation (SI) 2 ALTER DATABASE AdventureWorks2012 SET ALLOW_SNAPSHOT_ISOLATION ON 3 GO 4 5 -- Check if SI is now enabled 6 SELECT name, snapshot_isolation_state, snapshot_isolation_state_desc 7 FROM sys.databases 8 WHERE database_id = DB_ID('AdventureWorks2012') 9 GO 10 11 USE AdventureWorks2012 12 GO 13 14 -- Setting the Isolation Level to Snapshot Isolation 15 SET TRANSACTION ISOLATION LEVEL SNAPSHOT 16 GO
小結
今天你學習了自SQL Server 2005起支持的2個樂觀隔離級別。提交讀快照隔離(Read Committed Snapshot Isolation (RCSI))提供你基於語句級別的隔離,快照隔離(Snapshot Isolation (SI))提供你基於事務級別的隔離,因為2個隔離級別使在永駐在TempDb里的版本存儲,對於TempDb你需要仔細計划和指定標准。
下周我會談下SQL Server 里鎖和阻塞發生的問題:鎖升級(Lock Escalations)。請繼續關注!