簡介
最近測試服務器進行數據歸檔,其間程序員發現一個問題,空間不足,我查看原因發現日志文件暴漲。然后將數據庫改為簡單恢復模式,但是依然存在這個問題。經過查詢資料發現了日志文件在簡單模式下依然增加的原因。
Simple概念
Simple恢復模式也叫做”Checkpoint with truncate log“,其實這個名字更形象,在Simple模式下,SQL Server會在每次checkpoint或backup之后自動截斷log,也就是丟棄所有的閑置日志記錄,僅保留用於實例啟動時自動發生的instance recovery所需的少量log,這樣做的好處是log文件非常小,不需要DBA去維護、備份log,但壞處也是顯而易見的,就是一旦數據庫出現異常,需要恢復時,最多只能恢復到上一次的備份,無法恢復到最近可用狀態,因為log丟失了。
Checkpoint
CheckPoint和lazyWriter一樣,都會將緩沖區內臟數據寫入到磁盤,同時在簡單恢復模式下截斷日志;lazyWriter緩存不足的時候會觸發執行,這里我們暫且不做討論。
針對CheckPoint我請教了Careyson以后總結出以下幾個觸發其執行的原因:
- 一些Internal CheckPoint時,比如說關閉數據庫實例等。
- 數據庫完整備份或差異備份(日志備份不會觸發checkpoint)。
- 數據庫恢復模式為簡單恢復模式下當日志文件使用超過70%時。
- CheckPoint執行的時間間隔閾值被足夠多的日志記錄超過。
- 手動執行CheckPoint。
場景描述:
Simple模式主要用於非critical的業務,比如開發庫和測試庫,那么這次由於測試環境的磁盤緊張我們也都采用了簡單模式。但是數據歸檔發生時依然產生了大量的日志,並且增加了磁盤占用,這又是什么原因那?因為我們在歸檔處理中使用了大量的insert和delete以及update操作,這樣話,短時間內產生了大量的日志,這個時候日志迅速增加;又因為在SQL Server中,CheckPoint是一個完整的過程,這個過程的耗時取決於臟數據的大小。一旦在很短時間內,日志的CheckPoint沒完成的時候日志增加超過了日志的規定上限。則將產生更多的日志。
如上所述,產生這個問題的原因就是:CheckPoint時間間隔閾值被足夠多的日志記錄超過,觸發CheckPoint才寫入磁盤。
下面這個實例來自於:
讓我們用一個腳本來實際的闡明這種行為。首先在一個測試數據庫中運行一下腳本創建一個測試表並填充一些數據。
測試數據庫設置:
1.設置為簡單的恢復模式。
2.日志的大小為100M。
3.日志文件的自動增長被禁用(因為觀察日志空間被用完的錯誤比檢查自動增長要容易)。
運行以下腳本,觀察資源競爭:
declare @change_size int
set @change_size = 100 -- 根據需要來調整這個值
declare @i int
set @i = 1
while @i < 100
begin
if @i % 2 = 0
update test set c = replicate('a', @change_size)
else
update test set c = replicate('b', @change_size)
select @i = @i + 1
end
反復根據修改@change_size來看結果,當我將@change_size改為120甚至更大時,得到了9002的錯誤信息,非常准確的告訴我數據庫的事務日志已滿。
通過上面這個引用的例子,很好地再現了問題的產生機制,那么我們怎么處理這個情況那?
解決
方案1:
強制執行CheckPoint。但是執行后有個很不好的影響,嚴重影響了存儲過程的執行時間。由此可知這樣做很消耗性能啊。
方案2:
縮短CheckPoint時間間隔閾值。
默認值是0,意味着由SQL Server來管理這個回復間隔。
也可以SQL語句實現這個功能:
方案3:
增大日志文件大小。
總結:
日志文件是一個雙刃劍,WAL機制很好的保證了數據的一致性和維護性。但是也產生了額外的性能和維護的成本的上升。需要我們根據實際情況去處理這些不同的情景。需要注意的是在TempDB中是不會產生日志的,除非手動執行。除此之外,並非所有的時間間隔后都會產生日志,因為當數據很少的時候有可能不觸發Checkpoint執行。