復制代碼 代碼如下:
CREATE DATABASE TruncateTest;
GO
USE TruncateTest;
GO
ALTER DATABASE TruncateTest 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
INSERT INTO t1 DEFAULT VALUES;
GO 1280
CHECKPOINT;
GO
復制代碼 代碼如下:
SELECT COUNT (*) FROM fn_dblog (NULL, NULL);
GO
復制代碼 代碼如下:
TRUNCATE TABLE t1;
GO
SELECT COUNT (*) FROM fn_dblog (NULL, NULL);
GO
復制代碼 代碼如下:
SELECT
[Current LSN], [Operation], [Context],
[Transaction ID], [AllocUnitName], [Transaction Name]
FROM fn_dblog (NULL, NULL);
通過日志可以看出第一條顯式開始Truncate Table事務,最后一條開始DeferredAlloc。正如你所見,Truncate操作僅僅是釋放了構成表的頁和區。
下面這個代碼可以查看日志具體所做操作的描述:
復制代碼 代碼如下:
SELECT
[Current LSN], [Operation], [Lock Information], [Description]
FROM fn_dblog (NULL, NULL);
GO
你可以看出為了快速恢復的目的而加的相關鎖(你可以在我的博文:Lock logging and fast recovery中了解更多)。
由上面日志看出,這個操作會對8個頁加相關的鎖,然后整個區一次性釋放。釋放過后會對相關的區加IX鎖,也就是不能再被使用,當事務提交后才會進行deferred-drop,因此也就保證了Truncate table操作可以回滾。
另外,如果表上存在非聚集索引.那么操作方式也是類似,都是交給一個后臺線程然后釋放表和索引的頁。釋放的最小單位就是每個分配單元。按照上面步驟你自己嘗試一下就應該能明白我的意思了。
PS:還有一個關于Truncate Table操作不能回滾的誤區,我在:Search Engine Q&A #10: When are pages from a truncated table reused?這篇文章中進行了詳細的解釋。
新聞熱點
疑難解答