先了解SQLServer需要保存的日志記錄:
1、所有沒有經過“檢查點”的日志記錄:
SQLServer定時執行(Checkpoint),保證“臟頁”被寫入硬盤。沒做Checkpoint的,可能是只在內存中修改,數據文件還沒同步。SQLServer要在硬盤的日志文件中有記錄,一邊異常重啟后重新修改。
2、所有沒有提交的事務所產生的日志及其后續的日志記錄:
所有日志都有嚴格順序,不能有跳躍。
3、要做備份的日志記錄:
如果恢復模式不是簡單模式,那么SQLServer會認為用戶是要去備份日志記錄的。所有沒備份的記錄都會保留。
4、有其他需要讀取日志的數據庫功能:
如事務型復制(Transactional Replication)和鏡像。
除以上的類型之外,其他類型會在Checkpoint時做截斷把占用的空間標志為可重用。如果重用空間足夠,是不會報告日志空間已滿。Checkpoint的頻率由服務器的“Recovery Interval”決定,默認為一分鍾左右。
通常日志不斷增長的原因有:
1、數據庫恢復模式不是簡單,但是沒有做日志備份:
在這種模式下,做完整備份和差異備份是不會截斷日志的。
2、數據庫上有一個很長時間都沒有提交的事務:
SQLServer不會干預前端程序的連接遺留事務在SQLServer中的行為。只要不退出,事務會一直存在,直到(此處原為知道,謝謝kalagooooo的細心發現,現以改正過來)前端主動提交或者回滾。此時做日志備份也沒用了。
3、數據庫上有一個很大的事務在運行:
如建立、重建索引。或者insert/delete大量數據。或者是服務器端游標沒有把數據及時取走。
4、數據庫復制或鏡像出了異常
要避免上述現象,來防止日志不斷增長。對於不會做日志備份的數據庫,設為簡單模式即可。如果是完整模式,一定要定期做日志備份。如果鏡像或復制除了問題,要及時處理,如果沒有處理,那么要暫時拆除復制或鏡像。程序設計時,也要避免事務時間過長、過多。
對於日志增長處理:
步驟1:檢查日志現在使用情況和數據庫狀態:
檢查日志使用百分比、恢復模式和日志重用等待狀態。從2005以后,sys.databases加入了log_reuse_wait(log_reuse_wait_desc)來反映不能階段日志的原因
Log_reuse_wait |
Log_reuse_wait_desc |
說明 |
0 |
NOTHING |
有可重用的虛擬日志文件 |
1 |
CHECKPOINT |
上次日志截斷后,未出現檢查點,或者日志頭部尚未跨一個虛擬日志文件移動范圍(所有模式) |
2 |
LOG_BACKUP |
要求日志備份將日志表頭前移(非簡單模式)。日志備份完成后,日志標頭將前移,並一些空間可能會變成可重用。 |
3 |
ACTIVE_BACKUP_OR_RESTORE |
數據庫備份或還原正在進行(所有模式) |
4 |
ACTIVE_TRANSACTION |
事務處於活動狀態(所有模式) |
5 |
DATABASE_MIRRORING |
數據庫鏡像滯后(完整模式) |
6 |
REPLICATION |
在事務復制中,與發布相關的事務仍未傳遞到分發數據庫(僅限於完整模式) |
7 |
DATABASE_SNAPSHOT_CREATEION |
正在創建數據庫快照(所有模式) |
8 |
LOG_SCAN |
正在進行日志掃描(所有模式) |
9 |
使用以下腳本檢查:
DBCC SQLPERF(LOGSPACE) GO SELECT name,recovery_model_desc,log_reuse_wait,log_reuse_wait_desc FROM sys.databases GO |
如果Log Space Used(%)很高,就要馬上定位為什么不能被清除。如果狀態為:LOG_BACKUP,就意味(此處原為以為,感謝kalagooooo的細心發現,現以改正過來)着SQLServer,意味着SQLServer等待着日志備份。要檢查是否需要做日志備份。
步驟2:檢查最久的活動事務:
如果大部分日志都在使用中且重用狀態為:ACTIVE_TRANSACTION,那么要看看最久的事務是誰申請的:
DBCC OPENTRAN GO SELECT * FROM sys.dm_exec_sessions AS t2 , sys.dm_exec_connections AS t1 CROSS APPLY sys.dm_exec_sql_text(t1.most_recent_sql_handle) AS st WHERE t1.session_id = t2.session_id AND t1.session_id > 50 |
執行后返回:
找出最久的事務之后,先要檢查是否有問題,如果有問題,那么最好從應用層面把事務提交或回滾。如果實在不行,那就使用KILL SPID來殺掉進程。