SQL Server中已滿事務日誌原因的檢測

對於SQL Server數據庫管理員來講,已滿事務日誌是一個瑣碎的,但又很常見的問題。它能引發事務的提前終止,甚至通過阻止所有事務的引入,從而引起系統的崩潰。對於數據庫管理員來說,關鍵是理解將要發生的情況,以便他們可以追蹤引起問題的原因。 事務日誌填充方式

  以下是一些可能引起事務日誌填滿的原因:

  填滿的,細節的,或者沒有在已滿恢復模式下進行的日誌備份,都會引起日誌逐漸地填充。

  進程中有活動的備份(備份被作爲事務一樣來處理),它會填充部分日誌,而事務將填充剩餘部分。

  長時間運行的活動事務,例如從來都不會產生提交的SPID,以及暫停或高速運行數據庫鏡像都會引發延遲。前者會引起事務不發送,如果在發送事務到鏡像服務器之後的較長時間內,才進行高速運行,則後者纔會發生。

  對於事務複製,如果複製延遲或失敗,事務日誌將不會被清除,因爲除非事務與日誌都提交併發送至分佈式數據庫,否則事務都不能被清除。

  如果進程中有一個數據庫快照,當它創建時,所有的事務都堆積在它後邊。

  簡單的響應方法

  需要解決已滿事務日誌的問題時,你可以從以下幾個選擇入手:

  ·你可以執行備份來消減日誌。事務日誌備份是最快的,但也可能是最慢的,這取決於系統性能以及日誌的大小。通常不推薦填滿的或細節的備份,這取決於在大小合適的系統中完成這些備份所需的時間。

  ·你可以向數據庫中添加額外的事務日誌文件並執行以上備份方法中的一種。當你在進行必要的備份時, 額外的事務日誌文件的添加可以爲你贏得額外的時間。當然,它也可在稍後被刪除。

  ·你可以將數據庫的模式切換到簡單恢復模式,它將自動清除日誌。但要記住,你將會丟失自最近一次已滿的/細節的事務日誌備份之前的事務歷史。

  ·正在填充日誌的活動事務可以連同一些系統進程被終止,以至不會被重新執行並填充日誌。當問題源被追蹤到,它將提供一些緩解,但它不應該被考慮爲一種解決方案。

  ·在查找系統緩慢的原因時,數據庫鏡像/複製可以關閉。

  根本原因的檢測

  當微軟的人員在討論減少已滿事務日誌的問題時,他們經常從問題的返回信息來解決問題。微軟通常不會幫助你學習如何找出並解決代碼問題,雖然這些代碼問題是潛在的根源。

  我們假定在同一數據庫中運行兩個事務.m1和n2:

  Transaction 1

  
begin tran m1

  
update tbl

  
set f1 = f1 + f1

  
update tbl

  
set f1 = f1 + f1

  
update tbl

  
set f1 = f1 + f1

  
-- rollback tran m1

  
Transaction 2

  
begin tran n2

  
update tblm

  
set txtval = Convert(varchar(4000), txtval + txtval)

  
update tblm

  
set txtval = Convert(varchar(4000), txtval + txtval)

  
update tblm

  
set txtval = Convertvarchar(4000), txtval + txtval)

  
--rollback tran n2

  首先,我想讓大家注意一下以上事務的名字(m1和n2)。你會發現,如果你爲事務命名,在系統中追蹤,以及在查找問題原因時會變得更容易。其可讀性也會更好。注意,我沒有提交或回滾事務——你在應用程序中控制事務時也會領會這個作用。

  執行以下SQL腳本,它會返回當前活動事務的列表:

  select * from sys.dm_tran_active_transactions

  結果集

  我們當前運行的兩個事務連同它們相應的名稱一起出現在列表中,這使得它們很容易就被識別出來。當事務開始時,可以很容易地從屏幕上將它們區別出來,所以你可以瞭解到它是否過期以及應用程序,調度等在沒有提交或回滾時是否被允許掛起。在事務類型列中,1表示:“讀/寫”,2表示“只讀”,3表示“系統”,4表示“分佈式”。通常,填充日誌的事務是1,但那取決於日誌來源的填充。如果日誌由用戶進程填充,它們將是類型1。

  sys.dm_tran_session_transactions—將活動事務列表中的事務ID與活動的SPID聯繫起來。

  sys.dm_tran_database_transactions—如果你只想查看一個數據庫,它會只把與事相關的那個數據庫列出來。它也會把聲明/狀態列出來。數據庫事務狀態:1、未初始化,3、已初始化,但沒有日誌記錄,4、產生了日誌記錄,5、事務準備,10、事務提交,11、事務回滾,12、事務處於即將提交的進程中。

  由於已滿事務日誌歸因於消耗空間的活動日誌實體,因此只有狀態4或狀態12會消耗日誌空間。

  列database_transaction_log_record_count顯示將要讀取的日誌記錄,也會顯示正在等待被複制的日誌記錄。Database_transaction_log_bytes_used顯示當前使用了多少空間,而Database_transaction_log_bytes_reserved則顯示使用提交的事務預留空間(在這種情況下,預留的空間大小比實際使用的更重要)。

  事務診斷T-SQL腳本—事務不必保持活動狀態,只要打開它就行了。

  以下T-SQL腳本可以在你所關注的數據庫中執行。它將向你提供以下內容:

  佔據數據庫空間的事務。

  初始觸發事務的T-SQL腳本。

  事務及事務中系統使用的大小(兆字節和字節)。

  事務的當前聲明或狀態。

  連同日誌編號的日誌記錄條數。

  即使請求還沒有被執行,此腳本仍可在事務打開後的任意時刻執行。

  CREATE TABLE #Tmp_Transaction(

  ID
int identity(11),

  
[TransactionName] [nvarchar](32) NOT NULL

  
[transaction_id] [bigint] NOT NULL

  
[transaction_begin_time] [datetime] NOT NULL

  
[transaction_type] [int] NOT NULL

  
[transaction_state] [int] NOT NULL

  
[session_id] [int] NOT NULL

  
[TranLog_MB_Used] [bigint] NULL

  
[TranLog_MB_Reserved] [bigint] NULL

  
[TranLogSys_MB_Used] [int] NULL

  
[TranLogSys_MB_Reserved] [int] NULL

  
[database_transaction_type] [int] NOT NULL

  
[database_transaction_state] [int] NOT NULL

  
[database_transaction_status] [int] NOT NULL

  
[database_transaction_status2] [int] NOT NULL

  
[database_transaction_log_record_count] [bigint] NOT NULL

  
[database_transaction_replicate_record_count] [int] NOT NULL

  
[database_transaction_log_bytes_used] [bigint] NOT NULL

  
[database_transaction_log_bytes_reserved] [bigint] NOT NULL

  
[database_transaction_log_bytes_used_system] [int] NOT NULL

  
[database_transaction_log_bytes_reserved_system] [int] NOT NULL

  
[database_transaction_begin_lsn] [numeric](250) NULL

  
[database_transaction_last_lsn] [numeric](250) NULL

  
[database_transaction_most_recent_savepoint_lsn] [numeric](250) NULL

  
[database_transaction_commit_lsn] [numeric](250) NULL

  
[database_transaction_last_rollback_lsn] [numeric](250) NULL

  
[database_transaction_next_undo_lsn] [numeric](250) NULL

  EventInfo
nvarchar( Max)

  
CREATE TABLE #inputb (EventType nvarchar( Max), Parameters int, EventInfo nvarchar Max)) -- hold buffer

  
declare @iRwCnt int

  
declare @i int

  
declare @iSPID int

  
declare @vSPID varchar(4)

  
set @i = 1

  
insert into #Tmp_Transaction(TransactionName, transaction_id,

  transaction_begin_time, transaction_type, transaction_state, session_id,

  TranLog_MB_Used, TranLog_MB_Reserved, TranLogSys_MB_Used, TranLogSys_MB_Reserved,

  database_transaction_type, database_transaction_state, database_transaction_

  status,

  database_transaction_status2, database_transaction_log_record_count,

  database_transaction_replicate_record_count, database_transaction_log_bytes_used,

  database_transaction_log_bytes_reserved,

  database_transaction_log_bytes_used_system,

  database_transaction_log_bytes_reserved_system, database_transaction_begin_lsn,

  database_transaction_last_lsn, database_transaction_most_recent_savepoint_lsn,

  database_transaction_commit_lsn, database_transaction_last_rollback_lsn,

  database_transaction_next_undo_lsn)

  
select at.name [TransactionName], at.transaction_id, at.transaction_begin_time,

  at.transaction_type, at.transaction_state, st.session_id,

  (dt.database_transaction_log_bytes_used
/1048576) [TranLog_MB_Used]

  (dt.database_transaction_log_bytes_reserved
/1048576) [TranLog_MB_Reserved]

  (dt.database_transaction_log_bytes_used_system
/1048576) [TranLogSys_MB_Used]

  (dt.database_transaction_log_bytes_reserved_system
/1048576)

  
[TranLogSys_MB_Reserved]

  dt.
[database_transaction_type], dt.[database_transaction_state]

  dt.
[database_transaction_status], dt.[database_transaction_status2]

  dt.
[database_transaction_log_record_count]

  dt.
[database_transaction_replicate_record_count]

  dt.
[database_transaction_log_bytes_used]

  dt.
[database_transaction_log_bytes_reserved]

  dt.
[database_transaction_log_bytes_used_system]

  dt.
[database_transaction_log_bytes_reserved_system]

  dt.
[database_transaction_begin_lsn]

  dt.
[database_transaction_last_lsn]

  dt.
[database_transaction_most_recent_savepoint_lsn]

  dt.
[database_transaction_commit_lsn], dt.[database_transaction_last_rollback_

  lsn
]

  dt.
[database_transaction_next_undo_lsn]

  
from sys.dm_tran_active_transactions at

  
inner join sys.dm_tran_session_transactions st on at.transaction_id =

  st.transaction_id

  
inner join sys.dm_tran_database_transactions dt on at.transaction_id =

  dt.transaction_id

  
where dt.database_id = DB_ID() and dt.database_transaction_state in (412) and

  st.is_user_transaction
= 1

  
set @iRwCnt = @@ROWCOUNT

  
while @i <= @iRwCnt

  
begin

  
select @iSPID = t.session_id from #Tmp_Transaction t where t.ID = @i

  
set @vSPID = Convert(varchar@iSPID)

  
truncate table #inputb

  
INSERT #inputb EXEC ( 'DBCC INPUTBUFFER (' + @vSPID + ') WITH NO_INFOMSGS'

  )

  
update t

  
set t.EventInfo = select top 1 EventInfo from #inputb)

  
from #Tmp_Transaction t

  
where t.ID = @i

  
set @i = @i+1

  
end

  
select TransactionName, transaction_id, transaction_begin_time, transaction_type,

  transaction_state, session_id, TranLog_MB_Used, TranLog_MB_Reserved,

  TranLogSys_MB_Used, TranLogSys_MB_Reserved, EventInfo, database_transaction_type,

  database_transaction_state, database_transaction_status,

  database_transaction_status2, database_transaction_log_record_count,

  database_transaction_replicate_record_count, database_transaction_log_bytes_used,

  database_transaction_log_bytes_reserved,

  database_transaction_log_bytes_used_system,

  database_transaction_log_bytes_reserved_system, database_transaction_begin_lsn,

  database_transaction_last_lsn, database_transaction_most_recent_savepoint_lsn,

  database_transaction_commit_lsn, database_transaction_last_rollback_lsn,

  database_transaction_next_undo_lsn

  
from #Tmp_Transaction

  
drop table #Tmp_Transaction

  
drop table #inputb

  事務T-SQL診斷—事務必須激活執行

  下一部分代碼是基於以上T-SQ腳本來編寫的,目的是提供一個完整的圖像。基本上講,它將爲你提供關於動態執行事務的相關信息:

  ·初始化T-SQL調用的相關信息。

  ·當前正在執行的初始化T-SQL調用的潛在信息。

  ·當前狀態/開始時間,完成百分比。

  SELECT st.Session_id, req.Blocking_Session_ID [Blocker], req.Wait_Type,

  req.Wait_Time
[WaitTimeMS], req.Wait_Resource, req.open_transaction_count,

  req.percent_complete, dt.transaction_id, dt.database_transaction_begin_time,
case

  
when dt.database_transaction_type = 1 then 'RW' when dt.database_transaction_type =

  
2 then 'R' whendt.database_transaction_type = 3 then 'Sys' else 'Unknown' end

  
[TranType]

  
case when dt.database_transaction_state = 1 then 'Not Initialized' when

  dt.database_transaction_state
= 3 then 'Initialized, but no logs' when

  dt.database_transaction_state
= 4 then 'Generated logs' when

  dt.database_transaction_state
= 5 then 'Prepared' when

  dt.database_transaction_state
= 10 then 'Committed' when

  dt.database_transaction_state
= 11 then 'Rolled Back' when

  dt.database_transaction_state
= 12 then 'In process of committing' else 'Unknown'

  
end [TranState]

  req. Status, req.Command, stxt.objectid
[ExecObjID]

  (
SUBSTRING(stxt. text,req.statement_start_offset/2,( CASE WHEN

  req.statement_end_offset
= -1 then LEN(CONVERT(nvarchar(max), stxt. text)) * 2 ELSE

  req.statement_end_offset
end -req.statement_start_offset)

  
/2)) [SubText], stxt. text

  req.statement_start_offset

  
FROM sys.dm_tran_database_transactions dt nolock)

  
inner join sys.dm_tran_session_transactions st nolock) on dt.transaction_id =

  st.transaction_id

  
inner join sys.dm_exec_requests req (nolock) on st.transaction_id =

  req.transaction_id

  
CROSS APPLY sys.dm_exec_sql_text(req. sql_handle) [stxt]

  
where dt.database_id = db_id() and st.is_user_transaction = 1

  以上爲你提供了快速解決事務日誌問題的相關知識與工具。既然我們已經討論瞭如何檢測事務日誌填充的來源,我希望你可以更有效地利用事務日誌來幫助其他人。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章