1 基本介紹
每個數據庫都具有事務日志,用於記錄所有事物以及每個事物對數據庫所作的操作。
日志的記錄形式需要根據數據庫的恢復模式來確定,數據庫恢復模式有三種:
- 完整模式,完全記錄事物日志,需要定期進行日志備份。
- 大容量日志模式,適用於批量操作的數據庫,可以以更壓縮的方式處理日志,需要定期進行日志備份。
- 簡單模式,也有日志文件,只是該模式下可以通過checkpoint自動重用virtual log file,所以日志文件會處於一直重復使用的過程,保持一定大小,但是,如果有一個事務啟動,很久沒有commit,那么從這個事務開始到最后commit的時間段內的事務日志存儲空間都無法checpoint自動重用,這時,你很可能看到一個很大的日志文件;注意,簡單模式下是無法進行日志備份。
數據庫里邊,任何對數據庫的讀寫都是在內存頁中找到對應的數據也,再做修改,如果內存頁中不存在數據頁,則從磁盤加載如內存中。當一個修改操作發生時,修改的將是內存頁中對應的數據頁面,同時也會實時記錄到日后文件ldf中。那么,什么時候數據會被同步到mdf文件呢,只有以下三種情況:
- 做checkpoint時,后續會專門整理checkpoint的相應文章;
- Lazy write運行時,即內存出現壓力,需要把內存中的數據頁寫入到磁盤,騰出內存空間;
- eager write時,即發生bulk insert和select into操作時。
DB中的事務日志記錄,可以給我們帶來很多好處,它可以支持以下操作:
- 恢復個別的事務。
- 在 SQL Server 啟動時恢復所有未完成的事務。
- 將還原的數據庫、文件、文件組或頁前滾至故障點。
- 支持事務復制。
- 支持高可用性和災難恢復解決方案:AlwaysOn 可用性組、數據庫鏡像和日志傳送。
2 對數據庫啟動的影響
當數據庫重啟或者還原到最后的時候,數據庫都會進入 recovery狀態,正常情況下,這個狀態持續時間在幾十秒間,但是特殊情況下,它會花費非常長的時間,甚至幾個小時,如果這個步驟失敗,數據庫則進入到掛起 suspect狀態,無法正常提供使用。
那么,當數據庫進入 recovery 的時候,它在操作些什么呢?
SQL SERVER日志會記錄所有修改記錄(數據的修改情況,不包含SQL語句),包括Begin Transaction和Commit / Rollback Transaction 操作。由於對事務日志的修改,要比數據文件的修改要快,所有會出現,數據修改更新到了日志文件,但是還沒有落盤到數據文件,那么這個時候數據庫就處於recovery狀態,同時對事務日志最近的一個checkpoint點以后的所有數據修改記錄做以下檢查:

所有檢查結束后,則會對數據庫做一個checkpoint的表示,並寫入事務日志中,表明日志文件跟數據文件已經同步結束,完成了recovery過程,數據庫可正常提供使用。這里需要注意一點,如果你數據庫最近一次checkpoint到現在的修改操作足夠多,那么將會耗費相對較長時間來檢查,同時也能夠在 error log中看到百分比標識的recovery完成進展,避免漫無目的的等待。
Error Log的檢查,可以通過圖形界面(見下圖)查看當前日志,也可以運行xp_readerrorlog 查詢。
1 /* 2 xp_readerrorlog參數說明 3 1. 存檔編號 4 2. 日志類型(1為SQL Server日志,2為SQL Agent日志) 5 3. 查詢包含的字符串 6 4. 查詢包含的字符串 7 5. LogDate開始時間 8 6. LogDate結束時間 9 7. 結果排序,按LogDate排序(可以為降序"Desc" Or 升序"Asc"),默認升序 10 */ 11 12 Exec xp_readerrorlog 0,1,Null,Null,'2017-02-16 10:53:32.300','2017-02-16 12:53:32.300'
假設出現這種情況,由於上線的重要程度遠遠重要過 數據丟失的情況,並且你跟所有部門溝通確認
可以承擔 data file跟log file之間的差異數據的丟失,那么你可以按以下步驟操作,嚴重建議不要這么操作,因為會帶來不可預估的數據丟失情況,如果你命懸一線,真打算放棄這部分數據,那么,可以按照以下操作:
1 #設置數據庫單用戶 2 alter database backupdb set single_user with rollback immediate 3 4 #設置數據庫緊急狀態 5 alter database backupdb set emergency with rollback immediate 6 7 #獲取事務日志的物理名和邏輯名后,重建日志文件 8 select name,physical_name from sys.master_fiels where database_id=db_id('backupdb') 9 alter database backupdb rebuild log on (name='事務日志的邏輯名',filename='事務日志的物理名詞') 10 11 #設置數據庫online 12 alter database backupdb set online with rollback immediate 13 14 #設置數據庫為多用戶 15 alter database backupdb set multi_user with rollback immediate
3 日志文件添加方式
日志記錄在 后綴名為 ldf的文件,允許有多個日志文件,但是不會並發分開記錄日志,而是使用填充滿一個日志文件后,再轉向一個日志文件,線性操作日志文件。
可以通過下方來添加 ldf文件,需要注意幾個地方:
- 初始大小,建議直接設置為 截斷日志的期間內最大值,比如,某DB 恢復模式是完整模式,每隔半個小時做一次事務日志備份且截斷日志,那么設置 日志文件大小的時候,取業務高峰期 每半小時的日志增長 最大值是5G,則可設置初始大小為 5G-7G之間;
- 增長大小,無論是 按比例增長還是按照MB增長,都不要設置過小,建議每次增長在100Mb左右,減少使用到自動增長,在最初設置的初始大小就滿足其增長需求 ,如果開始設置的 初始大小 偏小,不滿足,可以挑一個業務低峰期,修改變大初始大小。每一次文件自動增長期間,都會對寫入的日志造成堵塞,雖然時間很短,但是如果增長頻繁,則會影響數據庫操作;
- 自動增長,建議設置為自動增長,但是前提定期監控日志的增長情況,避免磁盤空間不足,同時,如果恢復模式是 完整模式或者大容量模式,還需定期做日志備份截斷日志,避免 事務日志已滿的9002錯誤;
- 路徑選擇,建議與 mdf 文件放在不同的磁盤上,分散IO,若是磁盤讀寫瓶頸不大,則可放在一個磁盤上;
添加方式有2種,如下:
1 USE [master] 2 GO 3 ALTER DATABASE [backupdb] 4 ADD LOG FILE ( 5 NAME = N'backupdb_log_1', 6 FILENAME = N'D:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA\backupdb_log_1.ldf' , 7 SIZE = 524288KB , 8 MAXSIZE = 1048576KB , 9 FILEGROWTH = 10240KB 10 ) 11 GO
4 物理結構
數據庫的事務日志映射在一個或者多個的物理文件上,從概念上講,日志文件是一系列的日志記錄;從物理上講,日志記錄序列被有效的存儲在實現事務日志的物理文件中。
SQL Server 數據庫引擎在內部將每一物理日志文件分成多個虛擬日志文件,即VLF(Virtual Log File),虛擬日志文件沒有固定大小,且物理日志文件所包含的虛擬日志文件數不固定。數據庫引擎在創建或擴展日志文件時
動態選擇虛擬日志文件的大小。數據庫引擎嘗試維護少量的虛擬文件。在擴展日志文件后,虛擬文件的大小是現有日志大小和新文件增量大小之和。
只有當日志文件使用較小的 size 和 growth_increment 值定義時,虛擬日志文件才會影響系統性能。如果這些日志文件由於許多微小增量而增長到很大,則它們將具有很多虛擬日志文件。這會降低數據庫啟動以及日志備份和還原操作的速度。
建議您為日志文件分配一個接近於最終所需大小的size值,並且還要分配一個相對較大的 growth_increment 值。
管理員不能配置或設置虛擬日志文件的大小或數量,但是
在VLF影響系統性能的情況下,可以嘗試縮小,通過收縮日志文件的方式
。
dbcc loginfo(dbname) 返回的行數,即為 VLF 文件個數,當status為0時,即該文件沒有被使用,還能寫入LOG,2表示已被使用,並且無法重用,這個時候,可以通過 backup Log 的形式,備份並截斷LOG文件,則可以回收 從最后一個0到最近一個2行的空間。
收縮日志文件或者減少VLF文件的方式如下,需要先備份日志文件,才可以有效進行收縮,在沒有備份日志文件的情況下,進行收縮,效果不大。詳見以下代碼:
1 #其行數及為VLF個數,status為0表示文件未用,為2表示已被使用,無法重用 2 dbcc loginfo 3 4 #備份日志 5 BACKUP LOG [backupdb] 6 TO DISK = N'D:\data\20170215_backupdb_log.trn' WITH NOFORMAT, NOINIT, NAME = N'backupdb-事務日志 備份', SKIP, NOREWIND, NOUNLOAD, STATS = 10 7 GO 8 9 #收縮日志文件,根據日志文件名來收縮500Mb,建議收縮大小是合理大小,參考上文的 初始大小 判斷 10 USE [backupdb] 11 GO 12 SELECT name FROM sys.database_files WHERE type_desc='log' 13 DBCC SHRINKFILE (N'jiankong_db_log' , 500) 14 GO 15 16 #其行數及為VLF個數,VLF文件減少 17 dbcc loginfo
事務日志是一種回繞的文件。假設,數據庫backupdb只有一個ldf文件,且剛好分成了5個虛擬日志,當我們開始使用數據庫的時候,邏輯日志從物理日志的最開始端向末端記錄,如下圖。
當出現checkpoint的時候,則會標注 最小恢復日志序列號 MinLSN,“MinLSN”是成功進行數據庫范圍內回滾所需的最早日志記錄的日志序列號。如下圖。
在MinLSN之前的所有虛擬日志文件VLF都可以被截斷,數據庫會在以下兩個事件后自行截斷日志:
-
簡單恢復模式下,在檢查點之后發生。
- 在完整恢復模式或大容量日志恢復模式下,如果自上一次備份后生成檢查點,則在日志備份后進行截斷(除非是僅復制日志備份)。
當截斷日志的時候,這些VLF就可以被釋放回收,邏輯日志的開頭也會移動到最后一個被階段VLF文件末端。
假設這個時候,在MinLSN位置后,發生了一個事務,一直沒有commit,導致VLF3,VLF4,VLF5都被使用,那么就會重用之前回收的VLF文件。
正常情況下,如果經常截斷舊的日志記錄,保持邏輯日志的末端不到達邏輯日志的開頭,滿足下一個檢查點之前船艦的所有新日志記錄都有足夠的空間存儲,那么日志文件將永遠不會被填滿,保持一定的大小,可通過定期備份事務日志來達到。
但是如果,邏輯日志的結尾跟開頭碰面了,那么當磁盤空間足夠的情況下,則按照 自動增大大小 指定的數量 增大日志文件,並在 物理日志文件中添加多個VLF文件;如果磁盤空間不足,比指定的 增量大小 要少,那么就會報錯,出現9002錯誤,導致數據庫無法進行所有寫操作。
5 延遲日志截斷原因
日志截斷會由於多種因素發生延遲。可查詢sys.databases目錄視圖的
log_reuse_wait 和
log_reuse_wait_desc 列來發現是什么(如果有)阻止了日志的截斷。 下表對這些列的值進行了說明。

6 管理事務日志
定期監控日志文件的大小跟實際使用大小,以防日志增長異常,占滿磁盤空間,可通過以下兩種方式查看 日志文件使用情況.
1 #查看日志使用情況,文件大小及實際使用大小 2 dbcc sqlperf(logspace) 3 4 #查看文件相關信息 5 select name,physical_name,size*8.0/1024 size_Mb,* from sys.database_files
定期日志備份,兩個備份的間隔是運行丟失數據的時間跨度,不要過於頻繁備份,會對數據庫IO造成一定影響。
1 BACKUP LOG [backupdb] 2 TO DISK = N'D:\data\20170215_backupdb_log.trn' WITH NOFORMAT, NOINIT, NAME = N'backupdb-事務日志 備份', SKIP, NOREWIND, NOUNLOAD, STATS = 10 3 GO
事務盡可能短,避免長時間開啟事務,或者忘記commit/roll back;
解決事務日志已滿問題(9002錯誤)
- 若是限制了文件最大值,在磁盤空間有剩余的情況下,增加日志文件的大小。
- 釋放磁盤空間以便日志可以自動增長。
- 在其他磁盤上添加日志文件。
- 備份日志后,收縮日志。
- 將日志文件移到具有足夠空間的磁盤驅動器。
參考文檔: