SQL Server誤區30日談-Day26-SQL Server中存在真正的“事務嵌套”

來源:互聯網
上載者:User

    本系列文章是我在sqlskill.com的PAUL的部落格看到的,很多誤區都比較具有典型性和代表性,原文來自T-SQL Tuesday #11: Misconceptions about.... EVERYTHING!!,經過我們團隊的翻譯和整理髮布在AgileSharp上。希望對大家有所協助。

 

誤區 #26: SQL Server中存在真正的“事務嵌套”

錯誤

 

    嵌套事務可不會像其文法表現的那樣看起來允許事務嵌套。我真不知道為什麼有人會這樣寫代碼,我唯一能夠想到的就是某個哥們對SQL Server社區嗤之以鼻然後寫了這樣的代碼說:“玩玩你們”。

    讓我更詳細的解釋一下,SQL Server允許你在一個事務中開啟嵌套另一個事務,SQL Server允許你提交這個嵌套事務,也允許你復原這個事務。

    但是,嵌套事務並不是真正的“嵌套”,對於嵌套事務來說SQL Server僅僅能夠識別外層的事務。嵌套事務是日誌不正常增長的罪魁禍首之一因為開發人員以為復原了內層事務,僅僅是復原內層事務。

    但實際上當復原內層事務時,會復原整個內層事務,而不是僅僅是內層。這也是為什麼我說嵌套事務並不存在。

    所以作為開發人員來講,永遠不要對事務進行嵌套。事務嵌套是邪惡的。

    如果你不相信我說的,那麼通過下面的例子就就會相信。建立完資料庫和表之後,每一條記錄都會導致日誌增加8K。

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:復原內部事務時僅僅復原內部事務?

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

 

    你可以看到得出的結果是2和2000,下面我來復原內部的事務,按照我們的猜想應該只復原1000條吧,但事實上你會得到如下結果:

ROLLBACK TRAN InnerTran;
GO

訊息 6401,層級 16,狀態 1,第 2 行
無法復原 InnerTran。找不到該名稱的事務或儲存點。

 

    好吧,由Books Online來看,我只能使用外部事務的名稱或是將事務名稱留空來進行復原,代碼如下:

ROLLBACK TRAN;
GO

SELECT @@TRANCOUNT, COUNT (*) FROM t1;
GO

 

    現在我得到結果是0和0。正如Books Online所言,這個復原操作將外部事務進行了復原並將全域變數@@TRANCOUNT設定為0。事務中所有的修改都被復原,如果想部分復原的話只能使用SAVE TRAN 和ROLLBACK TRAN。

   

測試 #2:嵌套事務中內部事務提交後會儲存內部事務的修改嗎?

BEGIN TRAN OuterTran;
GO

BEGIN TRAN InnerTran;
GO

INSERT INTO t1 DEFAULT Values;
GO 1000

COMMIT TRAN InnerTran;
GO

SELECT COUNT (*) FROM t1;
GO

 

    正如我所期待,得到的結果是1000。這說明內部事務提交是會修改到磁碟的。但是如果這時外部交易回復的話,那麼不應該復原內部事務…

ROLLBACK TRAN OuterTran;
GO

SELECT COUNT (*) FROM t1;
GO

 

    但運行上面查詢後結果是0,這說明外部事務的復原會影響內部事務。

 

測試 #3:提交嵌套的事務的內部事務至少可以讓我清除日誌吧。

   在開始這個測試之前我首先清除了日誌,然後運行如下代碼:

BEGIN TRAN OuterTran;
GO

BEGIN TRAN InnerTran;
GO

INSERT INTO t1 DEFAULT Values;
GO 1000

DBCC SQLPERF ('LOGSPACE');
GO

   得到結果:

   

 

    下面我將事務提交後運行CheckPoint(對於簡單復原模式的資料庫將會截斷日誌),得到的結果:

COMMIT TRAN InnerTran;
GO

CHECKPOINT;
GO

DBCC SQLPERF ('LOGSPACE');
GO

 

   

 

    我們發現日誌的使用不減反贈,這是由於日誌寫入了CheckPoint記錄(詳情請看:How do checkpoints work and what gets logged)。提交內部事務不會導致日誌被清除,這是由於外部交易回復時也會連同內部事務一起復原(譯者註:所以這部分VLF在外部事務提交之前永遠不會被標記位reusable)。所以這部分日誌在外部事務提交之前永遠不會被截斷。為了證明這一點,我提交外部事務,然後再來看日誌:

COMMIT TRAN OuterTran;
GO

CHECKPOINT;
GO

DBCC SQLPERF ('LOGSPACE');
GO

 

 

    怎麼樣,日誌使用百分比大幅下降了吧。

    對於嵌套事務來說---Just Say no。(這句話你可以當作來自SQLSkill.com的一個熱心的傢伙給的福利)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.