sql server 日志文件結構及誤操作數據找回


一. 概述

  在sql server 里有數據文件.mdf和日志文件.ldf,日志文件是sqlserver數據庫的另一個重要組成部分,日志文件記錄了所有事務以及每個事務對數據庫所做的修改。為了提高數據庫的性能, sqlserver 數據是緩存在內存里,並沒有實時寫入到磁盤,直到數據庫出現檢查點(checkpoint)或者內存不足必須(Lazy Write)將數據的修改寫入到磁盤。 sql server在開啟了事務並對內存中的數據進行修改時,會生成日志記錄。 sqlserver 對數據頁的插入修改刪除都是在內存中完成后提交事務,但並不會同步到硬盤的數據頁上。 為了保證數據庫事務的一致性 如(服務器崩潰,斷電)等 內存中的修改沒有來得及寫入硬盤,下次重啟時候要能夠恢復到一個事務一致的時間點,就必須依賴於事務日志。

     1.1 存儲結構

  與數據文件不同 日志文件不是按頁/區來進行組織的。每個物理日志文件是分成多個虛擬日志單元,虛擬日志單元沒有固定大小,且數量不固定, 管理員也不能配置大小和數量。 例如:日志文件每自動增長一次(默認是按10%的空間擴展),會至少增加一個虛擬單元。

  事務日志是一種回繞的文件。例如一個數據庫里的日志文件包括5個虛擬日志單元,在創建數據庫時,邏輯日志文件從物理文件的始端開始,新的日志記錄被添加到邏輯日志未端,然后向物理日志未端擴張。

  當邏輯日志的末端到達物理日志的末端時,新的日志記錄將回繞到物理日志文件的始端繼續向后寫(這是因為日志備份會截斷使日志空間重用)。

  下圖是日志文件的流程圖,當日志備份后虛擬日志1和虛擬日志2會被截斷,虛擬日志3成為了邏輯日志的開頭,當虛擬日志3和虛擬日志4在使用后,再次備份時,由於日志文件是一個回繞的文件,此時又從虛擬日志1開始。
   圖1  日志文件的外觀

  

  圖2 事務日志的循環使用

     

   在一個虛擬日志單元里,分成很多塊,塊內有具體的日志記錄,每條日志記錄有一個LSN(Log Sequence Number)編號,這個編號由三部分組成。第一部分是虛擬日志單元(Virtual Log File)序列號,第二部分是在虛擬日志單元中塊的編號,第三部分是在塊中日志記錄的編號。對於某個LSN,其編號為000001D:000000FD:0002。 這表明這個LSN是屬於虛擬日志000001D,該虛擬日志中屬於塊000000FD,在該塊中對應記錄2。

  1.2 DBCC LOG
  使用DBCC LOG來查看日志文件里存放了些什么信息, dbcc log(dbname, formart_id),formart_id 使用"3" 參數輸出會比較詳細。

Create database TestLog
go
use TestLog
go
Create Table Test(ID int,name nvarchar(50))
GO
Insert into Test Values(1,'aaaa')
update Test set name='bbbb' where ID=1
Go
dbcc traceon (3604)
go
dbcc log (TestLog,3)

  由於dbcc log是未公開的命令,所以未找到相關說明, 如下圖所示 包括了當前序號號,操作類型,事務號等相關信息。

 二. ApexSQL Log工具

  由於dbcc log數據不太直觀,現通過第三方工具ApexSQL Log來查看,該工具可以看到對上面表的創建,插入,更新,刪除的操作記錄,在數據庫日志文件里還標注了起始時間表,以及操作由哪個用戶執行的,對於每一個操作,可以看到更具體的更新信息。

    這是剛剛操作的二條記錄如下圖所示

    

  選中insert 該行可以找到該語句做undo (撤消回滾 舊值覆蓋)和redo(提交 新值覆蓋)

  

-- Undo   INSERT (0000001E:00000047:0013) done at 2018-07-29 09:49:55.570 by hsr-PC\hsr in transaction 0000:00000301 (Committed)
BEGIN TRANSACTION
DELETE FROM [dbo].[Test] WHERE /*** WARNING: WHERE CLAUSE FOR THIS STATEMENT WAS GENERATED FOR A TABLE WITH NO PRIMARY KEY AND NO CLUSTERED INDEX ***/[ID] = 1 AND [name] = N'aaaa' COLLATE Chinese_PRC_CI_AS
IF @@ROWCOUNT <= 1 COMMIT TRANSACTION ELSE BEGIN ROLLBACK TRANSACTION; PRINT 'ERROR: STATEMENT AFFECTED MORE THAN ONE ROW. ALL THE CHANGES WERE ROLLED BACK.' END
--Redo    INSERT (0000001E:00000047:0013) done at 2018-07-29 09:49:55.570 by hsr-PC\hsr in transaction 0000:00000301 (Committed)
INSERT INTO [dbo].[Test] ([ID], [name]) VALUES (1, N'aaaa' COLLATE Chinese_PRC_CI_AS)
-- 下面ID=1的語句做四做操作
update Test set name='cccc' where ID=1
update Test set name='dddd' where ID=1
update Test set name='eeee' where ID=1
delete from  Test  where ID=1

 下列記錄了相應的操作,trial restricted 可能是因為該軟件需要付費。

  總結: 使用truncate table 來刪除操作是不會記錄日志的,且無法做undo操作。日志記錄與實際修改的數據量有關,每一條記錄的修改都會保存日志記錄。sql server日志里面能讀到數據修改前的值和修改后的值。

 

參考文獻:

  sq lserver2012實施與管理實戰指南


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM