剛刪除一個數據庫時,在清理數據庫備份歷史記錄時,執行超過近10分鍾還未完成,隨時查了下,嚇死寶寶啦,邏輯讀操作竟然高達8000萬次以上!
通過UI進行刪除數據庫時,會默認勾選上“刪除數據庫備份和還原歷史記錄信息”,作為多年的老司機,刪除數據庫應該寫腳本進行刪除,即使使用UI刪除,也應該不勾選該選項,但一時偷懶,直接點執行,導致該操作消耗大量邏輯IO和CPU並持續10分鍾還不能成功完成。
勾選上“刪除數據庫備份和還原歷史記錄信息”后,會執行下面語句:
EXEC msdb.dbo.sp_delete_database_backuphistory @database_name = N'monitor' GO
執行該存儲過程后,會在msdb數據庫中嵌套地刪除備份相關的N張表,其中一條刪除語句如下:
DELETE msdb.dbo.backupmediafamily FROM msdb.dbo.backupmediafamily bmf WHERE bmf.media_set_id IN ( SELECT media_set_id FROM @media_set_id ) AND ( ( SELECT COUNT(*) FROM msdb.dbo.backupset WHERE media_set_id = bmf.media_set_id ) = 0 )
當備份和還原歷史記錄信息較多的時候,刪除操作消耗的資源會成幾何數增長,由於該服務器用作日志傳送服務器,承載很多個數據庫的日志傳送,因此相關備份表中存有大量數據,導致刪除操作長時間不能完成。
解決辦法:
定期執行下面腳本來清理備份還原數據:
--設置歷史記錄保存期限為1天 DECLARE @keepMinutes BIGINT SET @keepMinutes= 60*24 DECLARE @expiredDT NVARCHAR(100) SELECT @expiredDT = dbo.ufn_FormatDate(DATEADD(MINUTE, 0 - @keepMinutes, GETDATE()), 'yyyy-MM-ddTHH:mm:ss') EXEC msdb.dbo.sp_delete_backuphistory @expiredDT EXEC msdb.dbo.sp_purge_jobhistory @oldest_date = @expiredDT EXEC msdb.dbo.sp_maintplan_delete_log NULL, NULL, @expiredDT
上面腳本中使用到一個日期格式轉換函數,代碼為:

/****** Object: UserDefinedFunction [dbo].[ufn_FormatDate] Script Date: 2015/11/24 19:40:45 ******/ DROP FUNCTION [dbo].[ufn_FormatDate] GO /****** Object: UserDefinedFunction [dbo].[ufn_FormatDate] Script Date: 2015/11/24 19:40:45 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO --==================================== --將時間轉換成制定格式的字符串 CREATE FUNCTION [dbo].[ufn_FormatDate] ( @Datetime DATETIME , @FormatMask VARCHAR(32) ) RETURNS VARCHAR(32) AS BEGIN DECLARE @StringDate VARCHAR(32) SET @StringDate = @FormatMask IF ( CHARINDEX('YYYY', @StringDate) > 0 ) SET @StringDate = REPLACE(@StringDate, 'YYYY', DATENAME(YY, @Datetime)) IF ( CHARINDEX('YY', @StringDate) > 0 ) SET @StringDate = REPLACE(@StringDate, 'YY', RIGHT(DATENAME(YY, @Datetime), 2)) IF ( CHARINDEX('MM', @StringDate) > 0 ) SET @StringDate = REPLACE(@StringDate, 'MM', RIGHT('0' + CONVERT(VARCHAR, DATEPART(MM, @Datetime)), 2)) IF ( CHARINDEX('DD', @StringDate) > 0 ) SET @StringDate = REPLACE(@StringDate, 'DD', RIGHT('0' + DATENAME(DD, @Datetime), 2)) IF ( CHARINDEX('HH', @StringDate) > 0 ) SET @StringDate = REPLACE(@StringDate, 'HH', RIGHT('0' + DATENAME(HH, @Datetime), 2)) IF ( CHARINDEX('mm', @StringDate) > 0 ) SET @StringDate = REPLACE(@StringDate, 'mm', RIGHT('0' + DATENAME(mm, @Datetime), 2)) IF ( CHARINDEX('ss', @StringDate) > 0 ) SET @StringDate = REPLACE(@StringDate, 'ss', RIGHT('0' + DATENAME(ss, @Datetime), 2)) IF ( CHARINDEX('ms', @StringDate) > 0 ) SET @StringDate = REPLACE(@StringDate, 'ms', RIGHT('0' + DATENAME(ms, @Datetime), 2)) RETURN @StringDate END --==================================== GO
沒多少技術含量,厚臉拿出來供初學者學習下!
============================================