检查点(Checkpoint)过程如何处理未提交的事务
每次我講解SQL Server之前,我都會(huì)先簡(jiǎn)單談下當(dāng)我們執(zhí)行查詢(xún)時(shí),在SQL Server內(nèi)部發(fā)生了什么。執(zhí)行一個(gè)SELECT語(yǔ)句非常簡(jiǎn)單,但是執(zhí)行DML語(yǔ)句更加復(fù)雜,因?yàn)镾QL Server要修改內(nèi)存中的相關(guān)頁(yè),并在事務(wù)日志里記錄整個(gè)事務(wù)。
介紹完這些特定步驟后,我總會(huì)問(wèn)同樣的問(wèn)題:當(dāng)我們有個(gè)未提交的事務(wù),這個(gè)時(shí)候剛好有檢查點(diǎn)(Checkpoint)發(fā)生,SQL Server會(huì)崩潰么?在我們數(shù)據(jù)文件里有我們未提交的數(shù)據(jù)么?先思考下,然后再寫(xiě)下你的答案。
創(chuàng)建測(cè)試場(chǎng)景
現(xiàn)在我想和你一起重建這個(gè)特定場(chǎng)景,最后你會(huì)看到你是否回答對(duì)了。這個(gè)場(chǎng)景的第一步,我創(chuàng)建了一個(gè)新的數(shù)據(jù)庫(kù),一個(gè)新的表,并插入一些記錄。
1 -- Create a new database 2 CREATE DATABASE Checkpointing 3 GO 4 5 -- Use it 6 USE Checkpointing 7 GO 8 9 -- Create a new table 10 CREATE TABLE Foo 11 ( 12 Col1 CHAR(100) NOT NULL, 13 Col2 CHAR(100) NOT NULL, 14 Col3 CHAR(100) NOT NULL 15 ) 16 GO 17 18 -- Insert a record 19 INSERT INTO Foo VALUES 20 ( 21 REPLICATE('A', 100), 22 REPLICATE('B', 100), 23 REPLICATE('C', 100) 24 ) 25 GO 26 27 -- Retrieve the record 28 SELECT * FROM Foo 29 GO在我們插入數(shù)據(jù)后,我想知道SQL Server存儲(chǔ)特定記錄的頁(yè)號(hào)。我們可以使用DBCC IND命來(lái)來(lái)返回特定表的所有頁(yè)。在我的服務(wù)器上SQL Server使用的Page id是79。
1 -- Retrieve the first data page for the specified table (columns PageFID and PagePID) 2 DBCC IND(Checkpointing, Foo, -1) 3 GO現(xiàn)在當(dāng)我們用DBCC PAGE命令輸出頁(yè)內(nèi)容時(shí)(使用這個(gè)命令前,要先啟用3604跟蹤標(biāo)記),我們可以看到插入的A,B,C的16進(jìn)制值。
1 -- Enable DBCC trace flag 3604 2 DBCC TRACEON(3604) 3 GO 4 5 -- Dump the first data page of the table Customers retrieved by DBCC IND previously 6 DBCC PAGE (Checkpointing, 1,79, 3) 7 GO現(xiàn)在當(dāng)我們進(jìn)行檢查點(diǎn)(Checkpoint)過(guò)程,并最終殺掉SQL Server會(huì)發(fā)生什么?未提交的數(shù)據(jù)會(huì)物理寫(xiě)入數(shù)據(jù)文件么?我們來(lái)試驗(yàn)下...
崩潰并恢復(fù)SQL Server
現(xiàn)在我們開(kāi)始一個(gè)新的事務(wù),并更新插入記錄的第一列。
1 -- Begin a new transaction without committing it... 2 BEGIN TRANSACTION 3 4 UPDATE Foo 5 SET Col1 = REPLICATE('X', 100)從代碼里你可以看到,我們并沒(méi)有提交這個(gè)事務(wù)!它還是待定的,未提交的事務(wù)。現(xiàn)在我們打開(kāi)另一個(gè)會(huì)話(huà),我們?nèi)藶檫M(jìn)行一次檢查點(diǎn)(Checkpoint)過(guò)程,并最終關(guān)閉SQL Server。
1 -- Execute it in a different session 2 CHECKPOINT 3 GO 4 5 SHUTDOWN WITH NOWAIT 6 GO現(xiàn)在你認(rèn)為未提交的事務(wù)已經(jīng)寫(xiě)入數(shù)據(jù)文件了么?不確定?我們來(lái)找出答案!我們?cè)?6進(jìn)制的編輯器(例如XVI32)里打開(kāi)數(shù)據(jù)文件。跳到頁(yè)號(hào)79的開(kāi)始。在數(shù)據(jù)文件里,頁(yè)號(hào)是物理偏移量,即頁(yè)開(kāi)始的地方——乘上8192字節(jié),因?yàn)樵赟QL Server里頁(yè)的大小是8kb。因此頁(yè)79的開(kāi)始整數(shù)偏移量是647168(79*8192).當(dāng)我們查看hex值時(shí),我們看到了我們未提交的數(shù)據(jù)。
檢查點(diǎn)(Checkpoint)過(guò)程不會(huì)區(qū)分提交和未提交的事務(wù)。它只會(huì)到緩存管理器(Buffer Manager)索取所有臟頁(yè),不管它們事務(wù)的狀態(tài)。
現(xiàn)在我們有不一致,損壞的數(shù)據(jù)庫(kù)了么?沒(méi)有,并不真的是。因?yàn)楝F(xiàn)在當(dāng)我們啟動(dòng)SQL Server,每個(gè)數(shù)據(jù)庫(kù)都經(jīng)過(guò)故障恢復(fù)階段,所有沒(méi)提交的事務(wù)都會(huì)回滾。當(dāng)SQL Server啟動(dòng)的時(shí)候,我們可以在SQL Server日志里看到這個(gè)行為:
小結(jié)
檢查點(diǎn)(Checkpoint)不會(huì)在意你的事務(wù)狀態(tài)。來(lái)自緩存池(Buffer Pool)的每個(gè)臟頁(yè)會(huì)寫(xiě)入數(shù)據(jù)頁(yè)。如果SQL Server崩潰了也沒(méi)關(guān)系,因?yàn)楣收匣謴?fù)能恢復(fù)你的數(shù)據(jù)庫(kù)到完全一致的狀態(tài)。我希望這篇日志能讓你更好的理解檢查點(diǎn)(Checkpoint)過(guò)程,還有它如何與未提交的事務(wù)打交道。
作為家庭作業(yè),你能否留言告訴我,還有哪些情形,SQL Server需要運(yùn)行故障恢復(fù)為你的數(shù)據(jù)庫(kù)還原到一致?tīng)顟B(tài)。在SQL Server里你知道多少個(gè)不同的場(chǎng)景呢?
參考文章:https://www.sqlpassion.at/archive/2016/01/25/how-the-checkpoint-process-deals-with-uncommitted-transactions/
轉(zhuǎn)載于:https://www.cnblogs.com/woodytu/p/5164359.html
總結(jié)
以上是生活随笔為你收集整理的检查点(Checkpoint)过程如何处理未提交的事务的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 雷观(六):码农值千金
- 下一篇: arcgis server 无法手动删除