|
公司之前一直存在一個規(guī)范,就是禁止嵌套事務的使用,一直不太明白為什么,試了下應該是無法控制回滾,今天看大牛的博客發(fā)現(xiàn),問題遠遠不只如此。 具體總結(jié)下來是以下3個問題 1、內(nèi)層事務回滾,只能回滾全部事務,無法控制單一事務回滾 2、內(nèi)層事務提交后,回滾外層事務,也會把內(nèi)層提交了的事務一起回滾 3、因為2的原因,只要整個事務不完全提交,日志空間都無法被釋放
嵌套事務可不會像其語法表現(xiàn)的那樣看起來允許事務嵌套。我真不知道為什么有人會這樣寫代碼,我唯一能夠想到的就是某個哥們對SQL Server社區(qū)嗤之以鼻然后寫了這樣的代碼說:“玩玩你們”。 讓我更詳細的解釋一下,SQL Server允許你在一個事務中開啟嵌套另一個事務,SQL Server允許你提交這個嵌套事務,也允許你回滾這個事務。 但是,嵌套事務并不是真正的“嵌套”,對于嵌套事務來說SQL Server僅僅能夠識別外層的事務。嵌套事務是日志不正常增長的罪魁禍首之一因為開發(fā)人員以為回滾了內(nèi)層事務,僅僅是回滾內(nèi)層事務。 但實際上當回滾內(nèi)層事務時,會回滾整個內(nèi)層事務,而不是僅僅是內(nèi)層。這也是為什么我說嵌套事務并不存在。 所以作為開發(fā)人員來講,永遠不要對事務進行嵌套。事務嵌套是邪惡的。 如果你不相信我說的,那么通過下面的例子就就會相信。創(chuàng)建完數(shù)據(jù)庫和表之后,每一條記錄都會導致日志增加8K。 CREATE DATABASE NestedXactsAreNotReal;
測試 #1:回滾內(nèi)部事務時僅僅回滾內(nèi)部事務? BEGIN TRAN OuterTran; INSERT INTO t1 DEFAULT Values; BEGIN TRAN InnerTran; INSERT INTO t1 DEFAULT Values; SELECT @@TRANCOUNT, COUNT (*) FROM t1;
你可以看到得出的結(jié)果是2和2000,下面我來回滾內(nèi)部的事務,按照我們的猜想應該只回滾1000條吧,但事實上你會得到如下結(jié)果: ROLLBACK TRAN InnerTran; 消息 6401,級別 16,狀態(tài) 1,第 2 行
好吧,由Books Online來看,我只能使用外部事務的名稱或是將事務名稱留空來進行回滾,代碼如下: ROLLBACK TRAN; SELECT @@TRANCOUNT, COUNT (*) FROM t1;
現(xiàn)在我得到結(jié)果是0和0。正如Books Online所言,這個回滾操作將外部事務進行了回滾并將全局變量@@TRANCOUNT設置為0。事務中所有的修改都被回滾,如果想部分回滾的話只能使用SAVE TRAN 和ROLLBACK TRAN。
測試 #2:嵌套事務中內(nèi)部事務提交后會保存內(nèi)部事務的修改嗎? BEGIN TRAN OuterTran; BEGIN TRAN InnerTran; INSERT INTO t1 DEFAULT Values; COMMIT TRAN InnerTran; SELECT COUNT (*) FROM t1;
正如我所期待,得到的結(jié)果是1000。這說明內(nèi)部事務提交是會修改到磁盤的。但是如果這時外部事務回滾的話,那么不應該回滾內(nèi)部事務… ROLLBACK TRAN OuterTran; SELECT COUNT (*) FROM t1;
但運行上面查詢后結(jié)果是0,這說明外部事務的回滾會影響內(nèi)部事務。
測試 #3:提交嵌套的事務的內(nèi)部事務至少可以讓我清除日志吧。 在開始這個測試之前我首先清除了日志,然后運行如下代碼: BEGIN TRAN OuterTran; BEGIN TRAN InnerTran; INSERT INTO t1 DEFAULT Values; DBCC SQLPERF ('LOGSPACE'); 得到結(jié)果: 下面我將事務提交后運行CheckPoint(對于簡單恢復模式的數(shù)據(jù)庫將會截斷日志),得到的結(jié)果: COMMIT TRAN InnerTran; CHECKPOINT; DBCC SQLPERF ('LOGSPACE');
我們發(fā)現(xiàn)日志的使用不減反贈,這是由于日志寫入了CheckPoint記錄(詳情請看:How do checkpoints work and what gets logged)。提交內(nèi)部事務不會導致日志被清除,這是由于外部事務回滾時也會連同內(nèi)部事務一起回滾(譯者注:所以這部分VLF在外部事務提交之前永遠不會被標記位reusable)。所以這部分日志在外部事務提交之前永遠不會被截斷。為了證明這一點,我提交外部事務,然后再來看日志: COMMIT TRAN OuterTran; CHECKPOINT; DBCC SQLPERF ('LOGSPACE');
怎么樣,日志使用百分比大幅下降了吧。 對于嵌套事務來說---Just Say no。(這句話你可以當作來自SQLSkill.com的一個熱心的家伙給的福利
轉(zhuǎn)載地址: http://www.cnblogs.com/CareySon/archive/2013/01/22/2871204.html
|
|
|
來自: 云端素館 > 《通用經(jīng)驗》