原文地址:http://rusanu.com/2012/07/27/how-to-shrink-the-sql-server-log/ html
說明:本文爲了更好的說明收縮的過程,在原文翻譯的基礎上增長了一些我的的理解,省略了部份內容,建議你們在閱讀本文時參考原文。 sql
1、問題場景 |
個人數據庫日誌文件已經增大到200G了,我也嘗試去收縮數據庫,但大小沒有改變,請問該如何減少日誌文件的大小?這個問題實際上就是說執行DBCC SHRINKFILE沒有減少日誌文件的大小,究竟是什麼緣由致使的呢? 數據庫
2、準備知識 |
一、LSN |
LSN用來標識特定日誌在日誌文件中位置(詳情請見什麼是LSN:日誌序列號),它由兩部分組成:一部分用來標識VLF(虛擬日誌文件)的序列號,剩下的用來標識該日誌在VLF中的具體的位置。 架構
根據LSN不一樣,日誌通常分爲兩類:首日誌(最新的活動日誌序號)和尾日誌(保留時間最長的活動日誌序號)。隨着數據庫的操做不斷增長(如數據庫中的update操做),首日誌LSN序號不斷變化。尾日誌的序號只有在日誌備份後纔會變化。 spa
(圖一)日誌文件結構圖操作系統
二、VLF |
你能夠經過DCC LOGINFO去分析數據庫LDF中VLF(虛擬日誌文件),LDF、VLF、日誌的關係是:LDF包括多個VLF,每一個VLF中包括多個日誌記錄。在VLF中,當事物日誌增長時,日誌的頭部(首日誌)不斷向前移動,日誌將佔用愈來愈多的剩餘空間,當這個VLF被佔滿後,新的日誌寫入到其餘未被使用的VLF中,這個時候LDF並不會增大。當LDF中沒有可用的VLF時,數據庫會建立一個新的VLF。從而使得LDF文件物理增大,佔用更多的磁盤空間。 翻譯
(圖二)日誌增加3d
3、解決方法詳細闡述 |
|
一、日誌的截斷 |
上圖演示了首日誌向前移動的場景,結合圖一和圖二能夠看到,當VLF2的空間被日誌填滿後,數據庫擴充LDF文件(向操做系統申請更多的磁盤空間),並在擴充後的LDF中新建一個VLF3用來填充新的日誌記錄。儘管VLF1中存在剩餘空間,但由於VLF1中存在活動日誌(哪怕只有一條),因此數據庫沒法利用這個VLF的剩餘空間,(詳細緣由能夠參考這篇文章什麼是LSN:日誌序列號)。 代理
這個時候作日誌備份就會發生日誌截斷的現象。通常會將截斷理解爲"刪除"一些日誌記錄(非活動),實際上它只是意味着尾日誌的向前移動:尾日誌序號會被刷新成最小的活動日誌序號,而從原來尾日誌的位置到新位置之間的空間被標記爲"可從新利用"。這個過程並不會減小LDF已佔用的磁盤空間。以下圖,整個VLF1的和部分VLF2上的日誌(非活動)被截斷了。 日誌
日誌截斷示意圖(圖三)
隨着事務日誌不斷增長,VLF3中日誌頭部所在的位置將不斷向前移動,當VLF3的空間被佔滿後,數據庫會從新利用VLF1的空間,這種寫入、截斷、再寫入的方式造成一個寫日誌的循環。在此期間LDF並不會物理上增大。
日誌循環使用示意圖(圖四)
二、爲何日誌不能收縮 |
如今咱們再來看一個日誌沒法收縮的場景:
圖四中,VLF1中的日誌不斷增長,直到VLF1的全部空間都被填滿(如圖五),此時由於沒有發生截斷,尾日誌都在VLF2上,且VLF2和VLF3都被標記爲不可從新利用,數據庫只能擴充LDF、新建一個VLF4用來記錄新的日誌,首日誌的位置將出如今VLF4中,整個寫日誌的(從圖一到圖四)順序爲VLF2——>VLF3——>VLF1——>VLF4。這個過程會致使數據庫的日誌文件在物理上增大。
日誌增加示意圖(圖五)
這時咱們再來截斷事物日誌,如上文所說,尾日誌的會被更新,最後可能出現尾日誌和首日誌在同一個VLF上的場景。從日誌文件記錄的架構上來看,咱們能夠將這個過程簡單地理解爲:截斷的順序會按照首日誌移動的順序移動,從VLF2——>VLF3——>VLF1——>VLF4,最終尾日誌和首日誌出如今同一個VLF上。
日誌截斷示意圖二(圖六)
如上圖,這個LDF文件包括3個空的和1個只有小部分活動日誌的VLF文件,首日誌和尾日誌在同一個VLF中,這種狀況下,試圖經過DBCC SHRINKFILE是不會減少LDF文件的大小的。
日誌文件能被收縮的緣由是該文件尾部的數據被清除了,使得該部分空間被釋放,而不是逃過尾部去刪除文件首部或者中間部分的內容。這點與MDF文件不一樣,MDF文件中的數據是不能被刪除的,只能將文件尾部的數據遷移到其餘區域的剩餘空間上,而後釋放尾部佔用的空間。
在LDF中 ,日誌是不能被遷移的,並且也沒有遷移的必要,由於當事物被提交後,日誌變爲不活動狀態,經過事物日誌備份便可將其截斷(特殊狀況下日誌備份不必定能截斷,如發佈訂閱的環境)。
綜上所述,日誌文件能被收縮的前提是:日誌文件的最後一個VLF必須是free狀態,從後向前推,只要是free狀態的VLF都會被收縮,據此能夠估算一個日誌文件能夠釋放的空間大小。
以下咱們看一個實際的例子:
USE DBname
DBCC loginfo
VLF狀態示意圖(圖七)
從上圖能夠看到,這個數據庫的日誌文件共有13個VLF,其中有前12個處於free狀態,最後1個處於活動狀態,所以,咱們能夠推斷首日誌和尾日誌的位置都在這個VLF上。這個時候執行文件收縮將看不到文件減少的效果。
三、如何解決這個問題 |
那麼碰到這種狀況,該怎麼去收縮日誌呢:儘量多的執行一些可以產生大量日誌的操做,這些日誌將致使數據庫從新利用startoffset靠前的非活動狀態的VLF,將首日誌的位置定位到這個startoffset,而後作一次事務日誌備份,將尾日誌也遷移到startoffset靠前的非活動狀態的VLF中,以下圖,最後再執行DBCC SHRINKFILE便可收縮日誌文件。
日誌截斷示意圖三(圖六)
4、重要說明 |
前文中一直在說經過日誌備份便可解決日誌截斷的問題,其實這只是最簡單的場景。在實際環境中可能有不少因素會影響日誌的截斷,如:
日誌備份只能截斷非活動的日誌,若是一個事物長時間運行,此時備份事物日誌將不會引發截斷髮生。
事物日誌分發中,只有當日志讀取器代理已經讀取完待分發的日誌後,日誌才能變得非活動狀態。(以前我處理過一個相似問題,你們能夠經過這個連接看看http://www.cnblogs.com/i6first/p/3281437.html。)
這兩種數據庫技術都須要將日誌傳遞到接受端,在傳遞尚未完成時,日誌會一直保留,即便是備份日誌也沒法截斷。