當一切正常時,沒有必要特別留意什麼是事務日誌,它是如何工做的。你只要確保每一個數據庫都有正確的備份。當出現問題時,事務日誌的理解對於採起修正操做是重要的,尤爲在須要緊急恢復數據庫到指定點時。這系列文章會告訴你每一個DBA應該知道的具體細節。sql
這篇文章會列出致使事務日誌過分增加的常見的問題和錯誤管理形式,包括:數據庫
固然,若是增加沒檢查,日誌文件會擴展直到吞沒全部可用磁盤空間或日誌文件的最大大小,在這個時候你會收到該死的9002錯誤(事務日誌已滿),數據庫會變成只讀。這篇文章會談處處理日誌不斷增加和9002錯誤的正確方法,還會解釋下一般建議截斷或收縮事務日誌爲何是危險的。安全
最後,咱們會談下保證你日誌文件是平穩和可預見增加的措施,還有日誌碎片的最小化問題。在忙碌的數據庫裏,大型的事務日誌會是一個簡單的生活事實,若是管理穩當的話,這並非件壞事,即便大部分時間日誌文件空間不可用。服務器
任什麼時候候日誌文件須要增加,額外的空間被分配,這個空間平均分到VLS裏,基於被分配空間數。網絡
例如,日誌文件默認會有2MB的初始大小,10%的自動增加率(來自model數據庫的配置)。這就是說,日誌文件開始至少會很小的增加,所以會有大量的小VLF。session
當咱們在很大的塊上分配額外空間時,例如當一次操做初始16GB的大小,結果事務日誌會有很小數量的VLF。架構
過高數量的小VLF,這樣的狀況稱爲日誌文件碎片,會影響到性能,尤爲在故障恢復,還原和備份,特別是日誌備份。換句話說,它會影響讀取日誌文件的操做性能。咱們會在第8篇詳細討論這個問題。併發
事務日誌VLF——太多仍是太少?異步
SQL Server MVP的Kimberly Tripp在他的文章裏討論了VLF大小的影響,並提供瞭如何恰當管理VLF大小的指導——事務日誌VLF—太多仍是太少?數據庫設計
相反,若是日誌文件只有幾個很大的VLF,咱們有長時間佔用大塊日誌的風險。每一個VLF都有很大數量的日誌記錄,SQL Server不能截斷VLF直到它沒有包含活動日誌。這個狀況下截斷會因某些緣由延遲(在缺乏日誌空間重用部分會詳細談到),這會致使日誌的快速增加。例如,咱們假設每一個VLF是1GB大小且日誌滿了。你進行了一第二天志備份,可是全部的VLF包含活動日誌的一部分,SQL Server不能截斷日誌。它沒有別的選擇只能增長更多VLF,若是日誌的增加率設置爲同等大小,那麼日誌增加會很快,直到有VLF變成可截斷。
所以,正確設置日誌初始大小很是重要,那它的增加纔會是合適的大小步驟,最小化日誌碎片也避免了過快增加。
正確設置初始大小且可控制它的增加的第2個緣由是:對於日誌文件,每一個增加是相對昂貴的操做。數據和日誌文件增加超時是正常的。SQL Server能夠優化增長新數據文件和擴展示有數據文件的過程,經過即時文件初始化(instant file initialization)(在SQL Server 2005引入,容許在磁盤上分配空間給數據文件,而不須要進行填零)。遺憾的是,對於日誌文件是不同的,對於日誌文件建立或增加的空間分配,仍是須要初始化且填零。
爲何事務日誌不能使用即時初始化?
進一步關注事務日誌填零,看下Paul Randal的文章:http://sqlskills.com/BLOGS/PAUL/post/Search-Engine-QA-24-Why-cant-the-transaction-log-use-instant-initialization.aspx
若是你經歷事務日誌的不可控增加,它因爲要麼是活動日誌頻率過高,要麼是有因素阻止日誌文件裏的空間重用,或者二者都有。
若是增加的主要緣由是活動日誌過多,你要檢查下是否能夠避免這個活動,例如調整處理大容量數據和索引維護的數據庫模式,這樣的話這些操做不會完整記錄(例如針對這些操做使用大容量日誌恢復模式)。可是,若是日誌備份裏包含有任何的最小化日誌操做,大容量操做會當即阻止數據庫到時間點的恢復(能夠閱讀下第6篇文章來得到更多詳細信息)。若是這是不可接受的,你必須直接接受大日誌的事實,根據具體狀況計劃它的增加和管理(例如日誌備份頻率),在接下來的穩當的日誌管理會介紹。
若是增加緣由是缺乏日誌空間的重用,你要找出什麼阻止這個重用並採起措施來修正這個問題。
索引維護操做是個很常見的致使事務日誌使用率過分和增加的緣由,尤爲數據庫運行在完整恢復模式裏。進行索引維護須要日誌空間量取決於下列因素:
當重建索引時,無論在線仍是離線,使用ALTER INDEX REBUILD,或是已經廢棄的SQL Server 2000裏的DBCC DBREINDEX,SQL Server新建立一個索引的副本,而後一旦重建完整,刪除老的副本(這是爲何你至少須要數據文件裏索引大小同樣的可用空間)
日誌記錄和在線索引重建
在SQL Server 2008和後續版本,在線索引重建是完整日誌操做,在SQL Server 2005裏是最小化日誌。所以,在後續SQL Server版本上進行這樣的操做本質上須要更多的事務日誌空間,能夠看下:https://support.microsoft.com/zh-cn/kb/2407439 還有Kalen Delaney的日誌,對於完整和大容量日誌2個恢復模式,驗證下在在線和離線索引重建期間的日誌記錄。
在完整恢復模式裏,索引重建能夠是很是佔資源的操做,須要事務日誌裏的不少空間。在簡單或大容量日誌恢復模式裏,重建索引是最小化日誌操做,這意味着只有分配被記錄,實際的頁並沒改變,所以經過這個操做減小了日誌空間量。
若是你切換到簡單模式進行索引重建,LSN鏈會當即中斷。你只能恢復你的數據庫到剛纔事務日誌備份裏的包含的時間點。爲了從新開始日誌鏈,你須要切換回完整恢復模式並當即進行一次完整或差別數據庫備份。
若是你切換到大容量日誌模式(看下第6篇),LSN鏈仍是連續的,但還會影響到進行時間點的恢復,由於包含最小化日誌操做的日誌備份不能用來恢復到時間點。若是能恢復到時間點的要求是至高無上的,那麼索引重建或任何最小化日誌操做不要使用大容量日誌恢復模式。除非在數據庫裏沒有同時發生的用戶活動,你可使用。否則的話,在可能的狀況下考慮在完整恢復模式裏進行索引重建。
若是使用的是大容量日誌模式,儘量使時間點恢復的時間最小,這樣能夠最小化暴露數據丟失風險。爲了作到這一點,在完整模式裏進行日誌備份,切換到大容量日誌,進行索引重建,而後切換回完整進行另外一個日誌備份。
最後一個重點要記住的是ALTER INDEX REBUILD操做是在一個單獨事務裏。若是索引很大,事務的執行時間會很長,在期間,這會阻止日誌裏的空間重用。這就是說,即便你在簡單模式裏重建索引,你也要想到自檢查點(CHECKPOINT)操做後日志應該保持很小,重建是最小化日誌,在劇烈的重建期間,日誌文件還會快速擴展。
和重建索引相比,使用ALTER INDEX REORGANIZE或者SQL Server裏的DBCC INDEXDEFRAG(已廢棄)重組(碎片整理)索引都是完整記錄操做,無論是任何恢復模式,所以實際的頁修改總被記錄。可是,一般索引重組比索引重建須要更少的日誌空間,儘管這是索引裏下降碎片的一個功能;比起輕度碎片,重度碎片索引會須要更多的日誌空間來重組。
另外,ALTER INDEX REORGANIZE操做是經過多個更短的事務完成的。所以,當與按期的日誌備份相結合(或在簡單恢復模式裏)時,在此操做期間,日誌空間能夠被重用,所以要求操做期間日誌空間最小化。
例如,對於重建操做,重建20GB的索引會須要超過20GB的空間,由於它發生在一個單獨的事務裏。可是,重組20GB的索引會須要更少的空間,由於在重組裏每一個頁分配修改是個單獨的事務,所以日誌記錄能夠用按期日誌備份截斷,讓日式空間能夠重用。
若是你的組織對任何潛在數據丟失不能容忍的,那麼你沒有選擇,只能讓全部的數據庫運行在完整恢復模式裏,而且穩當計劃你的日誌大小和增加。所以索引重建是做爲一個單獨線程發生的,日誌至少會和你重建的索引同樣的大小。如剛纔所說,索引重組會須要更少的空間,且容許在操做期間經過日誌備份來截斷日誌。這樣的話,爲了同時避免日誌暴漲,可行的話,你能夠用日誌重組。
若是你的SLA和操做級別協議(Operational Level Agreements(OLAs))容許一些潛在的數據丟失,那麼在索引重建前l切換到大容量日誌恢復模式能夠爲重建索引最小化空間需求量。可是,要在最小化數據丟失的方式下進行,例如已經討論確認過了。
無論使用的恢復模式,你能夠經過重組索引而不是重建索引來在日誌上最小化索引維護操做的影響。能夠的話,能夠看下微軟的指導方針,爲了最小化索引維護操做的影響,對於絕大數狀況,並非全部狀況,決定何時進行索引重建,何時進行索引重組(查看索引重組和重建)。他們也聲明:對於碎片級別大於5%且小於30%,你應該重組索引,對於碎片級別大於30%,你應該重建它。
可是,在索引維護期間,在保護日誌過分增加里,最有效的武器是維護那些真正須要的索引。使用SSMS維護計劃嚮導,索引維護是個背注一擲的操做:要麼重建(或重組)數據庫裏(維護計劃裏的全部數據庫)的全部索引,要麼全不維護。一個更好的方法是使用sys.dm_db_index_physical_stats的DMV來看下碎片程度根據須要來決定索引重建/重組策略。
Ola Hallengren的免費維護腳本
Ola Hallengren提供一個綜合的免費維護工具,它展現瞭如何使用sys.dm_db_index_physical_stats進行索引分析來進行智能維護,它能夠用來代替SSMS裏嚮導建立的數據庫維護計劃(https://ola.hallengren.com/)。
可是最好的方法,是計劃只維護那些能夠在查詢上提供真正持久影響的索引。邏輯碎片(在亂序中的索引頁)挫敗了SQL Server的預讀機制(https://msdn.microsoft.com/zh-cn/library/ms191475%28v=sql.105%29.aspx),且使在磁盤上讀取連續頁I/O-效率更低。可是,這隻真正影響從磁盤的大範圍掃描。即便對很是大碎片的索引,若是你不掃描表,重建或重組索引不會提升性能。下降頁深度(經過頁分裂或刪除形成的不少缺口)會帶來更多的頁佔用磁盤空間,且在內存裏,會須要更多的I/O帶寬來傳輸數據。再說一次,這個碎片格式不會真正影響不頻繁修改的索引,所以重建它們不會有幫助。
計劃索引維護前,問下本身什麼性能標準從維護受益?它會大會減小I/O?它會提升你最昂貴查詢的多少性能?它是持久正面影響麼?若是這些答案是「否」或「不知道」,那麼按期索引維護可能不是個長遠的答案。最後,值得注意的是對小索引維護是不值得的。一般引用的閾值是近1000頁。在微軟,當Paul Randal管理存儲引擎開發團隊時,建議這些值做爲參考,在在線幫助裏記錄了。注意,儘管這只是個建議並不對全部環境合適,如Paul在他的博客文章裏談到的:「在線幫助的索引碎片閾值來自哪裏?」
sys.dm_tran_database_transactions的DMV提供在事務日誌上事務活動影響的有用內部信息。在他們的書裏,《使用SQL Server動態管理視圖進行性能調優》,獲得他們的容許後,複製在這裏,做者Louis Davidson和Tim Ford,演示瞭如何使用這個DMV和一些其餘的,來調查可能形成事務日誌過分增加的事務。
在代碼7.1裏的例子重用來自第6篇的FullRecovery數據庫和PrimaryTable_Large表。在一個顯性事務裏,它重建了彙集索引而後調查日誌增加。
1 USE FullRecovery 2 GO 3 BEGIN TRANSACTION 4 5 ALTER INDEX ALL ON dbo.PrimaryTable_Large REBUILD 6 7 SELECT DTST.[session_id], 8 DES.[login_name] AS [Login Name], 9 DB_NAME (DTDT.database_id) AS [Database], 10 DTDT.[database_transaction_begin_time] AS [Begin Time], 11 DATEDIFF(ms, DTDT.[database_transaction_begin_time], GETDATE()) 12 AS [Duration ms] , 13 CASE DTAT.transaction_type 14 WHEN 1 THEN 'Read/write' 15 WHEN 2 THEN 'Read-only' 16 WHEN 3 THEN 'System' 17 WHEN 4 THEN 'Distributed' 18 END AS [Transaction Type], 19 CASE DTAT.transaction_state 20 WHEN 0 THEN 'Not fully initialized' 21 WHEN 1 THEN 'Initialized, not started' 22 WHEN 2 THEN 'Active' 23 WHEN 3 THEN 'Ended' 24 WHEN 4 THEN 'Commit initiated' 25 WHEN 5 THEN 'Prepared, awaiting resolution' 26 WHEN 6 THEN 'Committed' 27 WHEN 7 THEN 'Rolling back' 28 WHEN 8 THEN 'Rolled back' 29 END AS [Transaction State], 30 DTDT.[database_transaction_log_record_count] AS [Log Records], 31 DTDT.[database_transaction_log_bytes_used] AS [Log Bytes Used], 32 DTDT.[database_transaction_log_bytes_reserved] AS [Log Bytes RSVPd], 33 DEST.[text] AS [Last Transaction Text], 34 DEQP.[query_plan] AS [Last Query Plan] 35 FROM sys.dm_tran_database_transactions DTDT 36 INNER JOIN sys.dm_tran_session_transactions DTST 37 ON DTST.[transaction_id] = DTDT.[transaction_id] 38 INNER JOIN sys.[dm_tran_active_transactions] DTAT 39 ON DTST.[transaction_id] = DTAT.[transaction_id] 40 INNER JOIN sys.[dm_exec_sessions] DES 41 ON DES.[session_id] = DTST.[session_id] 42 INNER JOIN sys.dm_exec_connections DEC 43 ON DEC.[session_id] = DTST.[session_id] 44 LEFT JOIN sys.dm_exec_requests DER 45 ON DER.[session_id] = DTST.[session_id] 46 CROSS APPLY sys.dm_exec_sql_text (DEC.[most_recent_sql_handle]) AS DEST 47 OUTER APPLY sys.dm_exec_query_plan (DER.[plan_handle]) AS DEQP 48 WHERE DB_NAME(DTDT.database_id) = 'FullRecovery' 49 ORDER BY DTDT.[database_transaction_log_bytes_used] DESC; 50 -- ORDER BY [Duration ms] DESC; 51 COMMIT TRANSACTION
(代碼7.1:調查重日誌寫入事務)
(插圖7.1:索引重建後日志活動結果)
順便提下,若是咱們用ALTER INDEX...REORGANIZE來運行這個例子,那麼在Log Bytes Used列的值會從近159M降爲近0.5M。
若是你懷疑缺乏日誌空間重用形成了日誌增加,你的第一個任務是找出什麼阻止了重用。開始經過查詢如代碼7.2所示的
,看下對於提到的數據庫log_reuse_wait_desc的列值錯誤信息是什麼。sys.databases
1 SELECT name , 2 recovery_model_desc , 3 log_reuse_wait_desc 4 FROM sys.databases 5 WHERE name = 'FullRecovery'
(代碼7.2:檢查下log_reuse_wait_desc的列值)
log_reuse_wait_desc的列值會展現爲何當前空間不被重用的緣由。若是你已經執行剛纔的例子(代碼7.1),那麼極可能FullRecovery數據庫在這列會顯示LOG_BACKUP值(下面會詳談)。
阻止日誌重用不止一個。sys.databases視圖只顯示其中一個緣由。所以它是解決問題的一個可能方法,再次查詢sys.database會看到log_reuse_wait不一樣的緣由。
在在線幫助裏列出了log_reuse_wait_desc全部可能值,但在這裏咱們只談最多見的緣由,解釋如何安全確保那個空間能夠被重用。
若是從sys.databases查詢,log_reuse_wait_desc的返回值是LOG_BACKUP,那麼你極可能遭受完整或大事務日誌的最多見緣由,即在完整恢復模式裏的數據庫(或次之,大容量日誌恢復模式),沒有進行事務日誌備份。
在SQL Server的不少版本里,model數據庫默認是完整恢復模式。由於model數據庫是建立全部新SQL Server用戶數據庫的模板,新的數據庫繼承自model的配置。
對於大多數生產數據庫,使用完整恢復模式是推薦的作法,由於它容許數據庫的時間點恢復,最小化災難事件的數據丟失。可是,接下來的常見錯誤是調整備份策略是隻有完整備份(或者有差別備份)而沒有按期的事務日誌備份。這個策略有2個大問題:
爲了進行時間點的恢復並控制日誌大小,咱們必須用數據庫完整或完整和差別備份連同事務日誌備份。對於咱們的FullRecovery數據庫,咱們能夠進行日誌備份,如代碼7.3所示,而後再次查詢sys.databases。
1 USE master 2 GO 3 BACKUP LOG FullRecovery 4 TO DISK = 'D:\SQLBackups\FullRecovery_log.trn' 5 WITH INIT 6 GO 7 8 SELECT name , 9 recovery_model_desc , 10 log_reuse_wait_desc 11 FROM sys.databases 12 WHERE name = 'FullRecovery'
(代碼7.3:解決日誌備份問題)
若是缺乏日誌備份是日誌增加問題的緣由,首先要作的是驗證問題數據庫是否真的須要運行在完整恢復模式。若是必需要能恢復數據庫到任意時間點或到災難事件前的一個時間點,則是必須的,或者必需要用完整恢復模式的另外一個緣由(例如數據庫鏡像)。若是在SLA裏目標恢復點( Recovery Point Objective (RPO) )爲最大15分鐘的數據丟失,那麼極可能你不能只進行完整數據庫備份和差別數據庫備份,必需要進行日誌備份。
可是,若是由於不須要而沒有進行日誌備份,那麼數據庫不該該運行在完整恢復模式;咱們能夠切換數據庫到簡單恢復模式,那事務日誌的不活動部分會自動標記爲可重用,在檢查點的時候。
若是數據庫須要運行在完整恢復模式,那麼開始日誌備份,或調查下備份須要的頻率。事務日誌的備份頻率取決於不少因素,例如數據修改的頻率,還有在災 難中,SLA上可接受的數據丟失程度。另外,你應該採起措施保證日誌增加是可控的,在未來是可預見的,在這篇文章裏的穩當的日誌管理部分會介紹。
若是log_reuse_wait_desc的返回值是ACTIVE_TRANSACTION,那麼你受到來自SQL Server裏完整或大的事務日誌的第二個常見緣由:長時間運行或未提交的事務。從新執行下來自代碼7.1的事務,但不提交,在從新執行下代碼7.3,你 會看到這個值返回(不要忘記回去提交這個事務)。
如在第2篇日誌截斷和空間重用部分介紹的,事務日誌裏的VLF只有在不包含活動日誌部分時纔會被截斷。若是數據庫試用完整或大容量日誌恢復模式,只 有日誌備份操做才能夠進行截斷。數據庫里長時間運行的事務延遲包含事務開始後生成的日誌記錄的VLF的截斷,包括其它併發事務對數據庫裏的數據修改產生的 日誌記錄,甚至當這些改變還沒提交時。另外,長時間運行的事務的空間需求量會經過對「補償日誌記錄」保留的空間增長,若是在系統裏事務回滾的話,這些日誌 記錄就會產生。這些保留是須要的,保證在回滾期間,這些事務能夠成功恢復而不會用完日誌空間。
另外一個常見對log_reuse_wait_desc值的活動事務值是「孤立」的顯式事務,它莫名其妙的從不提交。容許用戶在事務裏輸入的應用程序就特別容易是這類問題。
形成長時間運行的事務的最多見操做,也是在數據庫裏生成大量日誌記錄,是從數據庫裏歸檔或清除數據。數據保持每每是數據庫設計裏過後的想法,常常是數據庫已經活躍一段時間後才考慮,是在服務器接近可用存儲的容量限制。
一般,當須要歸檔時,第一個反應是從數據庫裏使用簡單的DELETE語句刪除不須要的數據,如代碼7.4所示。爲了生成一些簡單的測試數據,這個腳本使用Jeff Moden的隨機數據生成器的簡化版本,簡單修改來生成日期到2012。
USE FullRecovery ; GO IF OBJECT_ID('dbo.LogTest', 'U') IS NOT NULL DROP TABLE dbo.LogTest ; SELECT TOP 500000 SomeDate = CAST(RAND(CHECKSUM(NEWID())) * 3653.0 + 37534.0 AS DATETIME) INTO dbo.LogTest FROM sys.all_columns ac1 CROSS JOIN sys.all_columns ac2 ; -- delete all but the last 60 days of data DELETE dbo.LogTest WHERE SomeDate < GETDATE() - 60
(代碼7.4:大容量數據刪除)
取決於要刪除的在日期範圍內存在的行數,這會變成引發日誌增加問題的長時間運行的事務,即便數據庫運行在簡單恢復模式。外鍵串聯約束的出現或審計觸 發器會惡化問題。若是其它表引用目標表,經過外鍵約束來級聯刪除,那麼SQL Server頁經過級聯約束來記錄刪除的行的細節。若是表上有DELETE觸發器,在觸發器執行期間,SQL Server也會記錄進行的操做。
爲了最小化在事務日誌上的影響,數據清理應該簡化爲更短,獨立的事務。有不少方法中斷長時間運行的事務爲小的批處理。若是表存在級別約束或DELETE觸發器,咱們能夠在循環內進行刪除操做,在一個時間刪除一天的數據,若是代碼7.5所示。注意,在這個簡單的例子裏,在咱們的表裏沒有足夠的行來驗證這個技術的使用,簡單的DELETE;清理幾百萬行數據更合適。也注意批量刪除的主要關心的是並非速度(代碼7.5會比代碼7.4運行更慢)。最要關心的是避免日誌過分增加和鎖升級。
DECLARE @StopDate DATETIME , @PurgeDate DATETIME SELECT @PurgeDate = DATEADD(DAY, DATEDIFF(DAY, 0, MIN(SomeDate)), 0) , @StopDate = DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()) - 60, 0) FROM dbo.LogTest WHILE @PurgeDate < @StopDate BEGIN DELETE dbo.LogTest WHERE SomeDate < @PurgeDate SELECT @PurgeDate = DATEADD(DAY, 1, @PurgeDate) END
(代碼7.5:將數據清除拆散爲小的事務)
使用這個方法清除數據,每一個刪除事務的持續時間是從表裏刪除一條記錄的時間,加上任何觸發器或級聯約束進行它們操做的時間。若是數據庫使用簡單恢復模式,下個檢查點會截斷這些清除產生的日誌記錄,只要在VLF裏沒有相關數據清理的活動日誌存在。
當在處理過程當中級聯約束或審計觸發器不是要考慮的,咱們可使用不一樣的方法來清理表上的數據,同時最小化事務。不是進行一點的DELETE操做,它會影響多少的數據,取決於指定日期裏存在的行數,在DELETE語句裏使用TOP運算符會限制每一個循環操做影響的行數。使用@@ROWCOUNT來捕獲DELETE操做影響的行數,運算符會在小的批處理語句裏清除數據,直到@@ROWCOUNT的值小於DELETE語句裏TOP子句裏指定的行數,如代碼7.6所示。
這個方法只有在沒有觸發器和級別約束時使用有效,否則的話@@ROWCOUNT的結果不是實際表刪除的行數,而是觸發器執行或經過強制級聯約束影響的行數。
1 DECLARE @Criteria DATETIME , 2 @RowCount INT 3 SELECT @Criteria = GETDATE() - 60 , 4 @RowCount = 10000 5 WHILE @RowCount = 10000 6 BEGIN 7 DELETE TOP ( 10000 ) 8 FROM dbo.LogTest 9 WHERE SomeDate < @Criteria 10 SELECT @RowCount = @@ROWCOUNT 11 END
(代碼7.6:對於數據清理在DELETE語句裏使用TOP運算符)
這些方法在SQL Server 2000,2005,2008的任何版本均可以使用,在數據清理期間最小化事務。
可是,若是你的數據庫是SQL Server 2005或2008企業版,且常常清理數據,那麼清理數據的更好方法是表分區,在列上篩選要刪除的數據。這會更小影響事務日誌,由於分區包含的數據會從錶轉出並清理,對SQL Server只是記錄區從新分配的操做。
管理存檔
這已是這個系列文章討論範圍以外了,自動歸檔方案。可是,一個可能的歸檔過程涉及分區,表之間的架構複製,容許一個表的一個分區能夠轉出到另外一個。在主要的OLTP表最小化數據的活動部分,但只減小修改的元數據的歸檔過程。Kimberley Tripp已經寫了一份具體的白皮書,叫作SQL Server 2005裏的表和索引分區,它談了劃窗技術(sliding window technique)。
默認狀況下,SQL Server會在隱性事務裏包裹任何數據修改語句來保證,在災難事件裏,SQL Server能夠回滾在故障點已經作出的修改,返回數據到一致的狀態。若是修改爲功,隱性事務會提交到數據庫。和自動發生的隱性事務相比,咱們建立顯性事務,在代碼包裹多個修改在一個事務裏,來保證全部的修改經過ROLLBACK命令能夠撤銷,或者經過COMMIT命令提交讓它持久。
當恰當使用時,顯性事務能夠保證多個表之間的數據修改做爲一個單位成功完成,或者所有都不修改。當使用不當時,無論怎樣,在數據庫裏孤立的事務仍是活躍的,阻止事務日誌的截斷,這會致使事務日誌增加或填滿。在SQL Server裏有不少孤立事務的緣由,這超出了這篇文章詳細介紹的範圍。可是,一些常見的緣由有:
一旦一個事務開始,它會保持活動直到建立的鏈接,事務觸發COMMIT或ROLLBACK語句,或者鏈接從SQL Server中斷(當使用綁定的連接,會容許會話共享鎖,這是個異常)。
如今的應用程序一般會使用鏈接池,在池裏保持與SQL Server的鏈接讓程序重用,即便當程序代碼在鏈接上調用Close()方法。當對孤立事務進行故障排除是理解最後一點很是重要,由於即便鏈接在加入或返回到應用程序鏈接池前被重置,數據庫裏打開的事務仍是繼續存在的,若是它們沒有正常結束的話。
事務相關的DMV提供大量的額外信息,無論當前事務的狀態和進行的操做。可是,一些DBA仍是使用DBCC OPENTRAN做爲識別是否爲孤立事務(或只是長時間運行的)爲形成日誌增加的根源的最快方法。
在DBCC OPENTRAN(DatabaseName)格式裏會接受數據庫名稱做爲輸入參數,數據庫名稱是用做檢查打開事務的數據庫名。若是數據庫裏有活動事務存在,命令會輸出相似以下的信息。
1 DBCC OPENTRAN (FullRecovery)
Transaction information for database 'FullRecovery'. Oldest active transaction: SPID (server process ID): 56 UID (user ID) : -1 Name : user_transaction LSN : (897:15322:1) Start time : Sep 18 2012 1:01:29:390PM SID : 0x010500000000000515000000fd43461e19525f12828ba628ee0a0000 DBCC execution completed. If DBCC printed error messages, contact your system administrator.
(代碼7.7:來自DBCC OPENTRAN的輸出信息範例)
DBCC OPENTRAN只輸出最先的活動事務,但主要表示事務是否爲活動的疑問是開始時間。通常來講,未提交的事務是打開很長時間纔會是形成事務日誌增加的緣由。
另外一個重要的信息是SPID(server process ID;在DMV裏這用session_id代替),這用來標識建立打開事務的會話。咱們能夠經過SPID判斷事務是真的孤立仍是隻是長時間運行的,經過查詢sysprocesses視圖(在SQL Server 2000裏)或者SQL Server 2005及後續版本里的sys.dm_exec_sessions和sys.dm_exec_connections的動態視圖,如代碼7.8所示。注意sysprocesses視圖在SQL Server 2005及後續版本仍是可用的,保持向後的兼容性。在運行代碼7.8時,在每一個查詢裏,直接用你看到的會話值替換session_id值(咱們註釋了幾列,只是爲了簡化輸出的可讀性)。
1 USE master 2 GO 3 SELECT spid , 4 status , 5 -- hostname , 6 -- program_name , 7 -- loginame , 8 login_time , 9 last_batch , 10 ( SELECT text 11 FROM :: 12 fn_get_sql(sql_handle) 13 ) AS [sql_text] 14 FROM sysprocesses 15 WHERE spid = 53 16 17 USE FullRecovery 18 GO 19 SELECT s.session_id , 20 s.status , 21 -- s.host_name , 22 -- s.program_name , 23 -- s.login_name , 24 s.login_time , 25 s.last_request_start_time , 26 s.last_request_end_time , 27 t.text 28 FROM sys.dm_exec_sessions s 29 JOIN sys.dm_exec_connections c ON s.session_id = c.session_id 30 CROSS APPLY sys.dm_exec_sql_text(c.most_recent_sql_handle) t 31 WHERE s.session_id = 53
(代碼7.8:使用DMV來識別孤立的仍是長時間運行的事務)
若是回話是runnable,running或suspended狀態,那麼可能問題的根源是長時間運行,而不是孤立的事務。可是,只有進一步的調查才能確認。頗有可能剛纔的事務失敗且鏈接重置,使用鏈接池,當前運行的語句不是打開事務所關聯的。
在SQL Server 2005和後續版本,咱們可使用sys.dm_tran_session_transactions和sys.dm_tran_database_transactions對打開的事務收集信息,包括事務開始事件,打開事務使用的日誌數,以及日誌空間使用字節數,如咱們剛纔代碼7.1所見。代碼7.9展現了一個簡單的版本,帶有範例輸出。
(代碼7.9:收集打開事務的信息)
除非應用程序設計來檢查,處理孤立的事務,清除事務的惟一方法是KILL會話,它會形成事務回滾,和鏈接中斷同樣,在下一第二天志備份期間,容許日誌裏的空間是能夠被重用的。可是,回滾的執行後果必需要理解的。
除了剛纔提到的緣由以外,還有其餘一些問題阻止日誌裏空間重用,致使日誌過分增加。這裏我會談其中的一些,這個問題的更多信息,能夠看下Gail Shaw的文章,爲何個人事務日誌滿了?
REPLICATION
在事務複製期間,日誌讀取代理的任務是讀取事務日誌, 查找關聯修改的日誌記錄,複製到訂閱者(例如,「待定的複製」)。一旦修改被複制,會標記日誌爲「已複製」。緩慢或延遲的日誌讀取活動會致使記錄剩爲「待 定的複製」很長時間,在此期間它們仍是活動日誌的一部分,所以母VLF不能被截斷。對於經過變動數據捕獲( Change Data Capture (CDC))功能須要的日誌記錄也有相似的問題存在。
無論任何狀況,sys.databases的 log_reuse_wait_desc列會顯示REPLICATION做爲問題根源。在事務磁盤陣列的輸出性能裏,這個問題自己也暴露了瓶頸。尤爲是, 在併發寫加載下的延遲讀取操做。寫入日誌文件會持續發生,但用日誌讀取代理相關的和日誌備份文件讀取的讀操做也要持續的。同一時間有持續的讀和寫發生,取 決於系統中的日誌活躍級別和活動日誌部分的大小,會致使磁頭隨機的I/O活動,由於磁頭須要改變位置來讀取活動日誌的頭,而後活動日誌的尾。咱們可使用性能監視器(PerfMon)裏磁盤計數器 Physical Disk\Disk Reads/sec 和 Physical Disk\Disk Writes/sec來故障排除這類問題,看下SQL Server的故障排除的免費電子書的第2章來進一步瞭解這個問題的細節:https://www.simple-talk.com/books/sql-books/troubleshooting-sql-server-a-guide-for-the-accidental-dba/
這些複製等待問題的故障排除的第一步是識別日誌讀取器,SQL 代理做業是否正常運行。若是不是的話,嘗試啓動它們。若是啓動失敗,你要找出爲何。
若是做業是運行的,可是複製一直等待,事務日誌快速增加,你須要找到一些方法讓相關的日誌標記爲「已複製」,這樣的話它們的母VLF能夠被重用。遺憾的是,沒有完美的解決方案來避免複製或在CDC環境裏的反作用,但你能夠嘗試下面方法中的一種。
記住直接切換到簡單恢復模式,但願能截斷日誌,是不行的,由於複製和CDC2個均不支持簡單恢復模式,仍是繼續須要日誌讀取器直到日誌讀取器的SQL代理處理完成處理。
快照複製架構改變問題
在SQL Server 2005裏使用快照複製有一個已知的問題,當架構修改時,它會致使應該標記爲複製的架構修改沒被標記。這個問題能夠看下這個文章的解決方法:http://blogs.msdn.com/b/sqlserverfaq/archive/2009/06/01/size-of-the-transaction-log-increasing-and-cannot-be-truncated-or-shrinked-due-to-snapshot-replication.aspx
當log_reuse_wait_desc column列顯示爲ACTIVE_BACKUP_OR_RESTORE做爲當前等待描述,長時間運行的數據庫完整或差別備份是最有可能致使日誌重用問題。在數據庫完整或差別備份期間,備份過程會延遲日誌截斷,這樣的話事務日誌的活動部分會被包含爲完整備份的一部分。在備份操做沒完成期間,容許修改到數據庫的頁,當備份用WITH RECOVERY恢復時,可讓數據庫恢復到一致的狀態。若是這樣的等待形成持續的問題,你會須要調查下優化備份過程的方式,例如提升備份性能(提供備份壓縮)或者提升硬盤I/O系統的性能。
當log_reuse_wait_desc column列顯示爲DATABASE_MIRRORING,做爲當前等待描述,異步數據庫鏡像操做可能致使日誌重用問題。
在異步鏡像裏,主上的事務只有一旦提交,相關的日誌記錄纔會傳輸到鏡像數據庫。對於異步數據庫鏡像,主的日誌不能截斷直到日誌記錄已傳輸。當鏡像問題發生時,主上大量的日誌記錄會保持爲活動日誌的一部分,阻止日誌空間重用,直到複製到鏡像完成。
對於異步數據庫鏡像,若是鏡像不可用咱們會看到DATABASE_MIRRORING,歸因於斷開或很是慢的鏈接,或鏡像會話的掛起。對於異步數據庫鏡像,在正常操做和鏈接問題期間,咱們會看到這個值。
在這個狀況下,首先我會檢查下受影響數據庫的鏡像會話狀態。若是它們沒有正確同步,那麼你須要在主和鏡像之間故障排除失敗鏈接的緣由。數據庫鏡像一個最多見的緣由,當證書用來保證安全終端時,是證書過時,須要從新頒發證書。進一步討論鏡像鏈接問題處理已經不是這個文章的討論範圍,除非數據庫已經正常同步,那麼日誌記錄會發送到鏡像,在主上事務日誌的活動部分會繼續增加,不能截斷直到中斷鏡像配置。
若是在主上的日誌率大大超過能夠傳送到鏡像的日誌率,那麼主上的日誌會快速增加。若是鏡像服務器用來作報表,經過建立快照,對鏡像驗證磁盤I/O配置沒有飽和,經過剛纔提升的性能監視器裏硬盤計數器。若是這是問題所在,中止鏡像服務器的服務器能夠臨時解決問題。若是問題是嚴格的大量事務,數據庫沒有運行在SQL Server 2008或更高,那麼升級能夠解決問題,由於可使用SQL Server 2008或更高版本的日誌流壓縮。
最好的方法是判斷鏡像問題的緣由並解決它。例如,調優生成大量日誌記錄的操做,例如大容量加載數據,或者重組索引,在操做期間能夠減小對系統的影響。
最壞的狀況,事務日誌管理不當或突發、快速的日誌增加會形成事務日誌增加,最後吞食完硬盤上全部可用空間。到這個時候就不能增加了,你會遇到9002錯誤,事務日誌滿錯誤,數據庫會變成只讀。
儘管這個問題很緊迫,冷靜面對很重要,避免這類接下來會提到的」無心識「的解決方法,處理不當或作不應作。顯然當前的問題是讓SQL Server能夠繼續寫日誌,經過生成更多可用空間。若是原由是缺乏日誌備份,第一個要作的是從新運行代碼7.1;若是log_reuse_wait_desc列返回值是 Log Backup,那麼和可能這是問題緣由。一個在MSDB數據庫裏對backupset表的查詢,如代碼7.10所示,會確認是否要在數據庫上進行一第二天志備份,還有上一第二天志備份的時間。
1 USE msdb ; 2 SELECT backup_set_id , 3 backup_start_date , 4 backup_finish_date , 5 backup_size , 6 recovery_model , 7 [type] 8 FROM dbo.backupset 9 WHERE database_name = 'DatabaseName'
(代碼7.10:哪一個備份已作,何時作的)
在type列,D表明數據庫備份,L表明日誌備份,I表明差別備份。若是沒有日誌備份,或者它們並不頻繁,那麼你最好的作法是進行一第二天志備份(這裏假定數據庫運行在完整或大容量日誌恢復模式)。但願,這個能釋放日誌裏的實在空間,而後你能夠進行合適的日誌備份計劃和日誌增加管理策略。
若是由於某些緣由不能進行日誌備份,例如磁盤空間不足,或者進行日誌備份的時間超過可接受的問題解決時間,那麼,取決於對問題數據庫的災難恢復策略,或許能夠經過臨時切換到簡單恢復模式來強制日誌截斷,這樣在檢查點的時候日誌中不活動的VLF會被截斷。而後你能夠切換回完整數據庫恢復模式,進行新的完整數據庫備份(或差別備份,這裏假定先前已經有一次完整備份)來從新開始用於時間點恢復的日誌鏈。固然,你仍是充分調查問題,來保證空間不會再次直接吞食完。還有記住這點,剛纔討論過的,若是阻止空間重用的問題不是日誌備份,那麼這個技術就無效了,由於這些記錄會保留在活動日誌裏,阻止截斷。
若是缺乏日誌備份不是問題,或者進行完日誌備份不能解決問題,那麼調查緣由可能會花更多的時間。最快和最簡單的方法是在日誌硬盤上增長更多的空間。這表示要清理掉其餘文件,或者增長當前日誌硬盤的容量,或者在不一樣的硬盤列裏增長額外日誌文件,但這會佔用你一點喘息的空間,你須要讓數據庫擺脫只讀模式,而後進行一第二天志備份。
若是日誌備份釋放空間失敗,你要找出什麼阻止了日誌裏的空間重用。調查下sys.databases(代碼7.1)來找出什麼阻止了日誌空間重用,採起合適的行動,如剛纔缺乏日誌空間重用部分介紹的。
若是這個啥都沒透露,你須要進一步調查找出什麼操做形成過分日誌致使日誌增加,如事務日誌過分增加部分介紹的。
最後,解決了任何空間重用問題,極可能咱們的日誌文件會在磁盤上佔用很大的空間。做爲一次性的測量,例如假定咱們採起措施保證往後日誌增加有妥善的管理(下一部分就會談到),是可使用DBCC SHRINKFILE來回收臃腫事務日誌文件使用的空間。在第8篇咱們會提供如何作的例子。
咱們要麼指定收縮日誌的文件target_size,要麼指定0位目標大小,讓日誌收縮的儘量小,而後當即使用ALTER DATABASE來調整到合適的大小。後者是推薦的方法,它會最小化日誌文件的碎片。碎片問題是你應該從不按期進行的DBCC SHRINKFILE任務的主要緣由,由於它只用來控制日誌大小;咱們會在下個部分詳細討論這個。
遺憾的是,在網絡上搜索」事務日誌滿「會返回大量論壇的帖子,博客文章,甚至不少複製於SQL Server網站的文章,那些建議矯正的方法,坦白說,很危險。咱們在這裏會談其中一些流行的建議。
這個方法,你清理了全部用戶的數據庫,分離數據庫(或者關閉它),刪除日誌文件(或重命名),而後從新附加數據庫,會引發新的日誌文件建立,它的大小由model數據庫決定。這能夠說是處理完整事務日誌的最可怕的方式。它會形成數據庫啓動失敗,數據庫爲RECOVERY_PENDING狀態。
取決於數據庫在日誌刪除時是否正常關閉,在數據庫正常部分的恢復階段,數據庫可能不能進行撤銷和重作操做,由於事務日誌已經丟失,不能返回數據庫爲一致的狀態。當日志文件丟失時,數據庫須要事務日誌來進行故障恢復,數據庫不能正常啓動,只能從最近的可用備份裏恢復數據庫,這就會致使數據丟失。
建立,分離,附加,修復可疑數據庫
在特定狀況下,能夠黑入現存的數據庫的配置,容許事務日誌重建,但這會破壞數據庫裏現有數據庫的完整性。這類操做是,最好是最後實在絕對無法恢復數據庫數據了,這是咱們這個系列文章不推薦的作法。至於如未嘗試黑入數據庫來看已刪除的事務日誌,能夠看下Paul Randal的文章:建立,分離,附加,修復可疑數據庫。
在SQL Server 2000 和2005,BACK LOG WITH TRUNCATE_ONLY是SQL Server支持的強制截斷事務日誌的方法,在數據庫運行在完整或大容量日誌模式。使用這個命令實際不會作日誌內容備份副本;在截斷VLF裏的記錄會忽略。所以,不像正常日誌備份,你在破壞你的LSN鏈,你只能恢復數據庫到先前任何日誌備份裏的時間點。還有,即便數據庫設置爲完整恢復模式,實際上,從那個點開始,會運行在自動截斷模式,在檢查點會繼續截斷不活動的VLF。爲了讓數據庫運行在完整恢復模式,從新開始LSN鏈,你須要進行一次完整(或差別)備份。
沒有意識到對災難恢復的影響的人們纔會常用這個命令,在SQL Server 2005裏已經廢棄,從SQL Server 2008開始已經移除這個命令了。遺憾的是,這個技術更陰險的版本,仍是繼續被支持,取而代之這個命令,那就是BACKUP LOG TO DISK='NUL',NUL是忽略任何數據寫入的「虛擬文件」。這個技術的真正扭曲是,不像BACKUP LOG WITH TRUNCATE_ONLY,SQL Server無論日誌記錄,直接忽略。就SQL Server而言,進行日誌備份後,日誌記錄會在備份文件裏安全存儲,這樣的話,LSN鏈是完整的,在活動日誌裏的不活動VLF能夠安全截斷。任何接下來,慣例的日誌備份會成功,但從故障恢復的角度來講是無用的,由於日誌備份文件丟失的話,數據庫只能恢復到上次標準日誌備份的時間點,在BACKUP LOG TO DISK='NUL'命令發出前。
不要使用這裏的任何技術。強制日誌截斷的正確方法是臨時切換數據庫導簡單恢復模式,如前所述。
如在處理事務日誌滿錯誤部分討論的,事務日誌在不多狀況下是由於管理不當形成的,日誌增加正被活動管理,使用DBCC SHRINKFILE來回收事務日誌佔用的空間是個能夠接受的操做。
但咱們毫不能把日誌收縮做爲平常,計劃維護操做的一部分。緣由是咱們每次收縮日誌,它會爲接下來的事務當即再次增加來存儲日誌記錄。如在日誌大小和增加部分討論的,事務日誌不能利用即時文件初始化,所以全部日誌增加引起SQL Server須要分配的存儲空間填零操做。另外,若是咱們依賴事務日誌自動增加(下部分會談到),在日誌文件了會彙集更多的VLF,這個日誌碎片會影響任何須要讀取這個日誌文件的進程性能,若是碎片實在太多,也會影響到數據修改性能。
對於事務日誌文件的最佳作法是預先設置好它的合適大小,這樣的話正常狀況下就不會增加。而後,監視它的使用率來決定是否須要人爲增加,容許你決定合適的增加大小且決定要添加到日誌文件裏的VLF的大小和個數。在第8篇咱們會具體討論。
沒有任何意想不到的操做或問題而致使不正常的日誌增加(複製問題,未提交的事務等等),若是事務日誌關聯的數據庫運行在完整恢復模式,還一直增加,其實只有2個緣由:
最好的作法,若是你不能經過減小它們之間的時間來增長日誌備份的頻率,當在加載的時,能夠人爲增長日誌文件大小而不是讓它自動增加,而後恢復原來大小。有大的咱們人爲增加的事務日誌文件,但有最小化數量的VLF並非個壞事,即便大部分時間日誌文件有空餘空間。咱們會在第8篇詳細討論這個。
對於SQL Server數據庫的操做,事務日誌很是重要,還有在災難事件裏能最小化數據丟失風險。在日誌瘋狂增加的狀況裏,甚至滿了,DBA須要快速診斷並解決問題,同時要保持冷靜也很是重要,避免不深思熟慮的反應,例如強制日誌截斷,還有計劃按期的日誌收縮,這隻會弊大於利。
很是感謝SQL Server故障排除的做者Jonathan Kehayias,電子書也是能夠下載的,爲本文提供了大量參考。
也感謝您這麼耐心圍觀完這篇文章,我真是擠牙膏同樣,熬了一個星期才能出一篇文章,感謝您的關注!!!