分享工作中遇到的問題積累經驗 事務日志太大導致insert不進數據
今天開發找我,說數據庫insert不進數據,叫我看一下
他發了一個截圖給我
然后我登錄上服務器,發現了可疑的地方,而且這個數據庫之前有一段經歷
在月初的時候這個數據庫曾經置疑過,啟動不起來
Could not redo log record (163041:116859:5), for transaction ID (0:-1175226963), on page (17:20633999), database 'xxrchives' (database ID 7). Page: LSN = (162930:20671:38), type = 2. Log: OpCode = 2, context 3, PrevPageLSN: (163041:116230:18). Restore from a backup of the database, or repair the database. During redoing of a logged operation in database 'xxxrchives', an error occurred at log record ID (163041:116859:5). Typically, the specific failure is previously logged as an error in the Windows Event Log service. Restore the database from a full backup, or repair the database. An error occurred during recovery, preventing the database 'xxxrchives' (database ID 7) from restarting. Diagnose the recovery errors and fix them, or restore from a known good backup. If errors are not corrected or expected, contact Technical Support. Setting database option EMERGENCY to ON for database xxxchives. The database 'xxxxchives' is marked EMERGENCY_MODE and is in a state that does not allow recovery to be run.
由于一些特殊的原因沒有做備份,數據庫大小差不多3TB,這里3TB是已經除去可用空間的了,里面只有幾張表,其中只有一張大表
修復語句如下
USE MASTER GO ALTER DATABASE [xxxrchives] SET EMERGENCY GO ALTER DATABASE [xxxxchives] SET SINGLE_USER WITH ROLLBACK IMMEDIATE GO DBCC CHECKDB('xxxxchives','REPAIR_ALLOW_DATA_LOSS') with tablock GO ALTER DATABASE [xxxxchives] SET ONLINE GO ALTER DATABASE [xxxxchives] SET MULTI_USER GO
數據相對來說不是非常重要,允許丟失一些數據
結果運行了差不多7天,業務也一度中斷了
其實有數據庫完整備份的話可以使用頁面還原的方法還原有問題的頁面,加上日志備份,而不用這么大工程的。。。
有經驗的SQLSERVER管理員應該知道最后我使用的方法如何拋棄有824錯誤的頁面,只保留正常的數據頁面,這個大表是做了表分區的,由于篇幅關系這里不具體說了
消息 824,級別 24,狀態 2,第 3 行 SQL Server 檢測到基于一致性的邏輯 I/O 錯誤 pageid 不正確(應為 6:33780000,但實際為 0:0)。在文件 'E:\DataBase\FG_xxxxive\FG_xxxxhive_Id_04_data.ndf' 中、偏移量為 0x0000406e240000 的位置對數據庫 ID 7 中的頁 (6:33780000) 執行 讀取 期間,發生了該錯誤。SQL Server 錯誤日志或系統事件日志中的其他消息可能提供了更詳細信息。這是一個威脅數據庫完整性的嚴重錯誤條件,必須立即糾正。請執行完整的數據庫一致性檢查(DBCC CHECKDB)。此錯誤可以由許多因素導致;有關詳細信息,請參閱 SQL Server 聯機叢書。
問題所在
這個數據庫運行在SQL2008上面,一直都是簡單模式,那么問題來了,由于當時checkdb的時間很長,積累了大量事務日志
但是,按道理處于簡單模式會自動截斷日志的,但是當時本人也沒有看,心里只想著數據庫馬上online
步驟一:今天開發找我插不進去數據也是因為這個,我運行了下面語句,這個語句是我找問題的時候一般都先用這個語句,因為在徐海蔚老師的書里面也建議先使用這個語句
SELECT * FROM sys.[sysprocesses]
結果發現
相當多的log等待
步驟二:我再運行下面腳本
-- ============================================= -- Author: <樺仔> -- Blog: <http://www.cnblogs.com/lyhabc/> -- Create date: <2014/4/18> -- Description: <統計各個數據庫的總大小V2 不包含數據文件> -- ============================================= SET NOCOUNT ON USE master GO DECLARE @DBNAME NVARCHAR(MAX) DECLARE @SQL NVARCHAR(MAX) --臨時表保存數據 CREATE TABLE #DataBaseServerData ( ID INT IDENTITY(1, 1) , DBNAME NVARCHAR(MAX) , Log_Total_MB DECIMAL(18, 1) NOT NULL , Log_FREE_SPACE_MB DECIMAL(18, 1) NOT NULL ) --游標 DECLARE @itemCur CURSOR SET @itemCur = CURSOR FOR SELECT name from SYS.[sysdatabases] WHERE [name] NOT IN ('MASTER','MODEL','TEMPDB','MSDB','ReportServer','ReportServerTempDB') OPEN @itemCur FETCH NEXT FROM @itemCur INTO @DBNAME WHILE @@FETCH_STATUS = 0 BEGIN SET @SQL=N'USE ['+@DBNAME+'];'+CHAR(10) + 'INSERT [#DataBaseServerData] ( [DBNAME] , [Log_Total_MB] , [Log_FREE_SPACE_MB ] ) SELECT '''+@DBNAME+''', str(sum(convert(dec(17,2),sysfiles.size)) / 128,10,2) AS Total_MB, SUM(( database_files.size - FILEPROPERTY(database_files.name, ''SpaceUsed'') )) / 128.0 AS free_space_mb FROM dbo.sysfiles as sysfiles INNER JOIN sys.database_files as database_files ON sysfiles.[fileid]=database_files.[file_id] WHERE sysfiles.[groupid] =0 AND database_files.[type] = 1;' EXEC (@SQL) FETCH NEXT FROM @itemCur INTO @DBNAME END CLOSE @itemCur DEALLOCATE @itemCur SELECT * FROM [#DataBaseServerData] DROP TABLE [#DataBaseServerData]
結果發現
上百G的日志文件
步驟三:我使用數據分析腳本也發現表里面的數據沒有增加,按F5刷新了很多次

--數據分析 CREATE TABLE #tablespaceinfo ( nameinfo VARCHAR(50) , rowsinfo BIGINT , reserved VARCHAR(20) , datainfo VARCHAR(20) , index_size VARCHAR(20) , unused VARCHAR(20) ) DECLARE @tablename VARCHAR(255); DECLARE Info_cursor CURSOR FOR SELECT '[' + [name] + ']' FROM sys.tables WHERE type = 'U'; OPEN Info_cursor FETCH NEXT FROM Info_cursor INTO @tablename WHILE @@FETCH_STATUS = 0 BEGIN INSERT INTO #tablespaceinfo EXEC sp_spaceused @tablename FETCH NEXT FROM Info_cursor INTO @tablename END CLOSE Info_cursor DEALLOCATE Info_cursor --創建臨時表 CREATE TABLE [#tmptb] ( TableName VARCHAR(50) , DataInfo BIGINT , RowsInfo BIGINT , Spaceperrow AS ( CASE RowsInfo WHEN 0 THEN 0 ELSE CAST(DataInfo AS decimal(18,2))/CAST(RowsInfo AS decimal(18,2)) END ) PERSISTED ) --插入數據到臨時表 INSERT INTO [#tmptb] ( [TableName] , [DataInfo] , [RowsInfo] ) SELECT [nameinfo] , CAST(REPLACE([datainfo], 'KB', '') AS BIGINT) AS 'datainfo' , [rowsinfo] FROM #tablespaceinfo ORDER BY CAST(REPLACE(reserved, 'KB', '') AS BIGINT) DESC --匯總記錄 SELECT [tbspinfo].* , [tmptb].[Spaceperrow] AS '每行記錄大概占用空間(KB)' FROM [#tablespaceinfo] AS tbspinfo , [#tmptb] AS tmptb WHERE [tbspinfo].[nameinfo] = [tmptb].[TableName] ORDER BY CAST(REPLACE([tbspinfo].[reserved], 'KB', '') AS BIGINT) DESC DROP TABLE [#tablespaceinfo] DROP TABLE [#tmptb]
步驟四:下面檢查 VLF

DBCC LOGINFO
有400多個VLF
步驟五:檢查一下log為什么不能重用的原因
SELECT DB_NAME([database_id]) AS dbname , [log_reuse_wait] , [log_reuse_wait_desc] FROM sys.[databases]
結果發現 數據庫做了復制,我接手的時候這個數據庫是不需要復制的,可能是以前的同事弄的
步驟六:我使用博客園里面i6first的文章把復制干掉《你還可以再詭異點嗎——SQL日志文件不斷增長》
EXEC sp_removedbreplication [xxxchives]
步驟七:然后再來收縮日志
USE [xxxxchives] GO DBCC SHRINKFILE (N'xxxxxchives_log' , 5000) GO
弄完之后,數據庫正常了,沒有log等待,數據也在不斷增加
總結
簡單幾個步驟:從發現問題到解決問題,有些人可能半天才能解決,有些人幾分鐘就可以解決,這就是積累經驗的重要性
我自己的做法是多看書,多看博客園,在QQ群里看一下大家的問題,這就是經驗了,快速解決問題的經驗
本人也喜歡將工作中遇到的問題寫在博客里面,以供大家參考,大家一起進步o(∩_∩)o
如有不對的地方,歡迎大家拍磚o(∩_∩)o
文章列表