誤區(qū) #26: SQL Server中存在真正的“事務(wù)嵌套”
錯誤
嵌套事務(wù)可不會像其語法表現(xiàn)的那樣看起來允許事務(wù)嵌套。我真不知道為什么有人會這樣寫代碼,我唯一能夠想到的就是某個哥們對SQL Server社區(qū)嗤之以鼻然后寫了這樣的代碼說:“玩玩你們”。
讓我更詳細的解釋一下,SQL Server允許你在一個事務(wù)中開啟嵌套另一個事務(wù),SQL Server允許你提交這個嵌套事務(wù),也允許你回滾這個事務(wù)。
但是,嵌套事務(wù)并不是真正的“嵌套”,對于嵌套事務(wù)來說SQL Server僅僅能夠識別外層的事務(wù)。嵌套事務(wù)是日志不正常增長的罪魁禍首之一因為開發(fā)人員以為回滾了內(nèi)層事務(wù),僅僅是回滾內(nèi)層事務(wù)。
但實際上當回滾內(nèi)層事務(wù)時,會回滾整個事務(wù),而不是僅僅是內(nèi)層。這也是為什么我說嵌套事務(wù)并不存在。
所以作為開發(fā)人員來講,永遠不要對事務(wù)進行嵌套。事務(wù)嵌套是邪惡的。
如果你不相信我說的,那么通過下面的例子就就會相信。創(chuàng)建完數(shù)據(jù)庫和表之后,每一條記錄都會導(dǎo)致日志增加8K。
復(fù)制代碼 代碼如下:
CREATE DATABASE NestedXactsAreNotReal;
GO
USE NestedXactsAreNotReal;
GO
ALTER DATABASE NestedXactsAreNotReal SET RECOVERY SIMPLE;
GO
CREATE TABLE t1 (c1 INT IDENTITY, c2 CHAR (8000) DEFAULT 'a');
CREATE CLUSTERED INDEX t1c1 ON t1 (c1);
GO
SET NOCOUNT ON;
GO
測試 #1:回滾內(nèi)部事務(wù)時僅僅回滾內(nèi)部事務(wù)?
復(fù)制代碼 代碼如下:
BEGIN TRAN OuterTran;
GO
INSERT INTO t1 DEFAULT Values;
GO 1000
BEGIN TRAN InnerTran;
GO
INSERT INTO t1 DEFAULT Values;
GO 1000
SELECT @@TRANCOUNT, COUNT (*) FROM t1;
GO
你可以看到得出的結(jié)果是2和2000,下面我來回滾內(nèi)部的事務(wù),按照我們的猜想應(yīng)該只回滾1000條吧,但事實上你會得到如下結(jié)果:
復(fù)制代碼 代碼如下:
ROLLBACK TRAN InnerTran;
GO
復(fù)制代碼 代碼如下:
消息 6401,級別 16,狀態(tài) 1,第 2 行
無法回滾 InnerTran。找不到該名稱的事務(wù)或保存點。
好吧,由Books Online來看,我只能使用外部事務(wù)的名稱或是將事務(wù)名稱留空來進行回滾,代碼如下:
復(fù)制代碼 代碼如下:
ROLLBACK TRAN;
GO
SELECT @@TRANCOUNT, COUNT (*) FROM t1;
GO
現(xiàn)在我得到結(jié)果是0和0。正如Books Online所言,這個回滾操作將外部事務(wù)進行了回滾并將全局變量@@TRANCOUNT設(shè)置為0。事務(wù)中所有的修改都被回滾,如果想部分回滾的話只能使用SAVE TRAN 和ROLLBACK TRAN。
測試 #2:嵌套事務(wù)中內(nèi)部事務(wù)提交后會保存內(nèi)部事務(wù)的修改嗎?
復(fù)制代碼 代碼如下:
BEGIN TRAN OuterTran;
GO
BEGIN TRAN InnerTran;
GO
INSERT INTO t1 DEFAULT Values;
GO 1000
COMMIT TRAN InnerTran;
GO
SELECT COUNT (*) FROM t1;
GO
正如我所期待,得到的結(jié)果是1000。這說明內(nèi)部事務(wù)提交是會修改到磁盤的。但是如果這時外部事務(wù)回滾的話,那么不應(yīng)該回滾內(nèi)部事務(wù)…
復(fù)制代碼 代碼如下:
ROLLBACK TRAN OuterTran;
GO
SELECT COUNT (*) FROM t1;
GO
但運行上面查詢后結(jié)果是0,這說明外部事務(wù)的回滾會影響內(nèi)部事務(wù)。
測試 #3:提交嵌套的事務(wù)的內(nèi)部事務(wù)至少可以讓我清除日志吧。
在開始這個測試之前我首先清除了日志,然后運行如下代碼:
復(fù)制代碼 代碼如下:
BEGIN TRAN OuterTran;
GO
BEGIN TRAN InnerTran;
GO
INSERT INTO t1 DEFAULT Values;
GO 1000
DBCC SQLPERF ('LOGSPACE');
GO
得到結(jié)果:
下面我將事務(wù)提交后運行CheckPoint(對于簡單恢復(fù)模式的數(shù)據(jù)庫將會截斷日志),得到的結(jié)果:
復(fù)制代碼 代碼如下:
COMMIT TRAN InnerTran;
GO
CHECKPOINT;
GO
DBCC SQLPERF ('LOGSPACE');
GO
我們發(fā)現(xiàn)日志的使用不減反贈,這是由于日志寫入了CheckPoint記錄(詳情請看:How do checkpoints work and what gets logged)。提交內(nèi)部事務(wù)不會導(dǎo)致日志被清除,這是由于外部事務(wù)回滾時也會連同內(nèi)部事務(wù)一起回滾(譯者注:所以這部分VLF在外部事務(wù)提交之前永遠不會被標記位reusable)。所以這部分日志在外部事務(wù)提交之前永遠不會被截斷。為了證明這一點,我提交外部事務(wù),然后再來看日志:
復(fù)制代碼 代碼如下:
COMMIT TRAN OuterTran;
GO
CHECKPOINT;
GO
DBCC SQLPERF ('LOGSPACE');
GO
么樣,日志使用百分比大幅下降了吧。
對于嵌套事務(wù)來說---Just Say no。(這句話你可以當作來自SQLSkill.com的一個熱心的家伙給的福利:-)
您可能感興趣的文章:- SQL Server誤區(qū)30日談 第29天 有關(guān)堆碎片的誤區(qū)
- SQL Server誤區(qū)30日談 第28天 有關(guān)大容量事務(wù)日志恢復(fù)模式的誤區(qū)
- SQL Server誤區(qū)30日談 第27天 使用BACKUP WITH CHECKSUM可以替代DBCC CheckDB
- SQL Server誤區(qū)30日談 第25天 有關(guān)填充因子的誤區(qū)
- SQL Server誤區(qū)30日談 第24天 26個有關(guān)還原(Restore)的誤區(qū)
- SQL Server誤區(qū)30日談 第23天 有關(guān)鎖升級的誤區(qū)
- SQL Server誤區(qū)30日談 第22天 資源調(diào)控器可以調(diào)控IO
- SQL Server誤區(qū)30日談 第21天 數(shù)據(jù)損壞可以通過重啟SQL Server來修復(fù)
- SQL Server誤區(qū)30日談 第20天 破壞日志備份鏈之后,需要一個完整備份來重新開始日志鏈
- SQL Server誤區(qū)30日談 第19天 Truncate表的操作不會被記錄到日志
- SQL Server誤區(qū)30日談 第18天 有關(guān)FileStream的存儲,垃圾回收以及其它
- SQL Server誤區(qū)30日談 第17天 有關(guān)頁校驗和的誤區(qū)
- SQL Server誤區(qū)30日談 第16天 數(shù)據(jù)的損壞和修復(fù)
- SQL Server誤區(qū)30日談 第15天 CheckPoint只會將已提交的事務(wù)寫入磁盤
- SQL Server誤區(qū)30日談 第14天 清除日志后會將相關(guān)的LSN填零初始化
- SQL Server誤區(qū)30日談 第13天 在SQL Server 2000兼容模式下不能使用DMV
- SQL Server誤區(qū)30日談 第12天 TempDB的文件數(shù)和需要和CPU數(shù)目保持一致
- SQL Server誤區(qū)30日談 第11天 鏡像在檢測到故障后瞬間就能故障轉(zhuǎn)移
- SQL Server誤區(qū)30日談 第10天 數(shù)據(jù)庫鏡像在故障發(fā)生后 馬上就能發(fā)現(xiàn)
- SQL Server誤區(qū)30日談 第9天 數(shù)據(jù)庫文件收縮不會影響性能
- SQL Server誤區(qū)30日談 第8天 有關(guān)對索引進行在線操作的誤區(qū)
- SQL Server誤區(qū)30日談 第7天 一個實例多個鏡像和日志傳送延遲
- SQL Server誤區(qū)30日談 第6天 有關(guān)NULL位圖的三個誤區(qū)
- SQL Server誤區(qū)30日談 第5天 AWE在64位SQL SERVER中必須開啟
- SQL Server誤區(qū)30日談 第4天 DDL觸發(fā)器就是INSTEAD OF觸發(fā)器
- SQL Server誤區(qū)30日談 第3天 即時文件初始化特性可以在SQL Server中開啟和關(guān)閉
- SQL Server誤區(qū)30日談 第2天 DBCC CHECKDB會導(dǎo)致阻塞
- SQL Server誤區(qū)30日談 第1天 正在運行的事務(wù)在服務(wù)器故障轉(zhuǎn)移后繼續(xù)執(zhí)行
- SQL Server誤區(qū)30日談 第30天 有關(guān)備份的30個誤區(qū)