SQL Server磁盘空间自动监控:再也不用每天手动查磁盘了
管理N台数据库服务器,每天手动检查磁盘空间?这个自动化方案让你彻底解放!
大家好。手头管着几十台数据库服务器,每天都要登录上去检查磁盘空间?太浪费时间了!今天分享一套磁盘空间自动监控告警方案,让服务器自己发现问题、主动发邮件通知你。
通过SQL Server作业每天定时执行存储过程,自动收集磁盘容量信息,当剩余空间低于阈值时,自动发送告警邮件。
USE master;GOIF EXISTS (SELECT 1 FROM sysobjects WHERE id = OBJECT_ID(N'sp_diskcapacity_alert1') AND OBJECTPROPERTY(id, 'IsProcedure') = 1) DROP PROCEDURE sp_diskcapacity_alert1;GOCREATE PROCEDURE sp_diskcapacity_alert1 @Threshold NUMERIC -- 告警阈值(剩余空间百分比,如20表示剩余<20%告警)ASBEGIN SET NOCOUNT ON DECLARE @Result INT DECLARE @objectInfo INT DECLARE @DriveInfo CHAR(1) DECLARE @TotalSize VARCHAR(20) DECLARE @OutDrive INT DECLARE @UnitMB BIGINT = 1048576 DECLARE @HtmlContent NVARCHAR(MAX) DECLARE @FreeRat NUMERIC DECLARE @EmailHead VARCHAR(120) -- 创建临时表保存磁盘信息 CREATE TABLE #DiskCapacity (DiskCD CHAR(1), FreeSize INT, TotalSize INT) -- 获取剩余空间 INSERT #DiskCapacity (DiskCD, FreeSize) EXEC master.dbo.xp_fixeddrives -- 开启OLE自动化(临时开启,用完关闭) EXEC sp_configure 'show advanced options', 1 RECONFIGURE WITH OVERRIDE EXEC sp_configure 'Ole Automation Procedures', 1 RECONFIGURE WITH OVERRIDE EXEC @Result = master.sys.sp_OACreate 'Scripting.FileSystemObject', @objectInfo OUT DECLARE CR_DiskInfo CURSOR LOCAL FAST_FORWARD FOR SELECT DiskCD FROM #DiskCapacity ORDER BY DiskCD OPEN CR_DiskInfo FETCH NEXT FROM CR_DiskInfo INTO @DriveInfo WHILE @@FETCH_STATUS = 0 BEGIN EXEC @Result = sp_OAMethod @objectInfo, 'GetDrive', @OutDrive OUT, @DriveInfo EXEC @Result = sp_OAGetProperty @OutDrive, 'TotalSize', @TotalSize OUT UPDATE #DiskCapacity SET TotalSize = @TotalSize / @UnitMB WHERE DiskCD = @DriveInfo FETCH NEXT FROM CR_DiskInfo INTO @DriveInfo END CLOSE CR_DiskInfo DEALLOCATE CR_DiskInfo EXEC @Result = sp_OADestroy @objectInfo -- 关闭OLE自动化 EXEC sp_configure 'Ole Automation Procedures', 0 RECONFIGURE WITH OVERRIDE EXEC sp_configure 'show advanced options', 0 RECONFIGURE WITH OVERRIDE -- 计算最小剩余比例 SELECT @FreeRat = FreeRate FROM ( SELECT ROW_NUMBER() OVER (ORDER BY FreeSize / (TotalSize * 1.0) ASC) AS RowIndex, CAST((FreeSize / (TotalSize * 1.0)) * 100.0 AS INT) AS FreeRate FROM #DiskCapacity ) T WHERE RowIndex = 1 -- 判断是否需要告警 IF @FreeRat <= @Threshold BEGIN IF @FreeRat > 10 AND @FreeRat <= 20 SET @EmailHead = '数据库磁盘容量告警(告警级别3)' ELSE IF @FreeRat >= 5 AND @FreeRat <= 10 SET @EmailHead = '数据库磁盘容量告警(告警级别4)' ELSE SET @EmailHead = '数据库磁盘容量告警(告警级别5)' SET @HtmlContent = N'' + N'' + @EmailHead + '' + N'' + N'' + CAST((SELECT td = DiskCD, '', td = STR(TotalSize*1.0/1024,6,2), '', td = STR((TotalSize - FreeSize)*1.0/1024,6,2), '', td = STR(FreeSize*1.0/1024,6,2), '', td = STR((TotalSize - FreeSize)*1.0/TotalSize*100,6,2), '', td = STR(FreeSize*1.0/TotalSize*100,6,2), '' FROM #DiskCapacity FOR XML PATH('tr'), TYPE) AS NVARCHAR(MAX)) + N'磁盘盘符总大小(GB)已用空间(GB)剩余空间(GB)已用比例(%)剩余比例(%)' EXEC msdb.dbo.sp_send_dbmail @profile_name = 'DataBase_DDL_Event', -- 改成你的邮件配置名 @recipients = 'dba@yourcompany.com', -- 改成收件人 @subject = '服务器磁盘空间告警', @body = @HtmlContent, @body_format = 'HTML' END DROP TABLE #DiskCapacityENDGO-- 使用示例:剩余空间低于20%时告警EXEC sp_diskcapacity_alert1 @Threshold = 20
USE [master]GOIF OBJECT_ID(N'dbo.sp_diskcapacity_alert2') IS NOT NULL DROP PROCEDURE dbo.sp_diskcapacity_alert2;GOCREATE PROCEDURE sp_diskcapacity_alert2 @Threshold NUMERIC -- 告警阈值(剩余空间百分比)ASBEGIN SET NOCOUNT ON DECLARE @HtmlContent NVARCHAR(MAX) DECLARE @FreeRat NUMERIC DECLARE @EmailHead VARCHAR(200) -- 创建临时表 CREATE TABLE #DiskCapacity (DiskCD CHAR(4), FreeSize INT, TotalSize BIGINT) INSERT INTO #DiskCapacity (DiskCD, FreeSize) EXEC master..xp_fixeddrives -- 开启xp_cmdshell EXEC sp_configure 'show advanced options', 1 RECONFIGURE EXEC sp_configure 'xp_cmdshell', 1 RECONFIGURE EXEC sp_configure 'show advanced options', 0 RECONFIGURE -- 获取总容量 CREATE TABLE #DriveInfo1(ID INT IDENTITY(1,1), DiskCD VARCHAR(12)) CREATE TABLE #DriveInfo2(ID INT IDENTITY(1,1), TotalSize VARCHAR(22)) INSERT INTO #DriveInfo1(DiskCD) EXEC xp_cmdshell 'wmic LOGICALDISK get name' INSERT INTO #DriveInfo2(TotalSize) EXEC xp_cmdshell 'wmic LOGICALDISK get size' DELETE FROM #DriveInfo1 WHERE ID=1 DELETE FROM #DriveInfo2 WHERE ID=1 UPDATE #DiskCapacity SET TotalSize = ( SELECT CAST(LEFT(N.TotalSize, LEN(N.TotalSize)-1) AS BIGINT)/1024/1024 FROM #DriveInfo1 M INNER JOIN #DriveInfo2 N ON M.ID = N.ID WHERE M.DiskCD IS NOT NULL AND LEN(M.DiskCD) > 1 AND #DiskCapacity.DiskCD = LEFT(M.DiskCD, LEN(M.DiskCD)-1) ) -- 关闭xp_cmdshell EXEC sp_configure 'show advanced options', 1 RECONFIGURE EXEC sp_configure 'xp_cmdshell', 0 RECONFIGURE EXEC sp_configure 'show advanced options', 0 RECONFIGURE -- 计算剩余比例并判断告警 SELECT @FreeRat = FreeRate FROM ( SELECT ROW_NUMBER() OVER (ORDER BY FreeSize / (TotalSize * 1.0) ASC) AS RowIndex, CAST((FreeSize / (TotalSize * 1.0)) * 100.0 AS INT) AS FreeRate FROM #DiskCapacity ) T WHERE RowIndex = 1 IF @FreeRat <= @Threshold BEGIN -- 构造HTML和发送邮件(同上) SET @HtmlContent = N'...' -- 参考方案一 EXEC msdb.dbo.sp_send_dbmail @profile_name = 'DataBase_DDL_Event', @recipients = 'dba@yourcompany.com', @subject = '服务器磁盘空间告警', @body = @HtmlContent, @body_format = 'HTML' END DROP TABLE #DiskCapacity, #DriveInfo1, #DriveInfo2ENDGO
只能获取剩余空间,适合按剩余容量阈值告警的场景:
USE [master]GOIF OBJECT_ID(N'dbo.sp_diskcapacity_alert3') IS NOT NULL DROP PROCEDURE dbo.sp_diskcapacity_alert3;GOCREATE PROCEDURE sp_diskcapacity_alert3 @DiskCapacity FLOAT -- 告警阈值(剩余空间GB,如5表示剩余<5GB告警)ASBEGIN DECLARE @FreeSize INT DECLARE @EmailHead VARCHAR(200) DECLARE @HtmlContent NVARCHAR(MAX) CREATE TABLE #DiskCapacity (DiskCD CHAR(4), FreeSize INT) INSERT INTO #DiskCapacity (DiskCD, FreeSize) EXEC master..xp_fixeddrives SELECT @FreeSize = MIN(FreeSize) FROM #DiskCapacity IF @FreeSize / 1024.0 <= @DiskCapacity -- 转换为GB比较 BEGIN IF @FreeSize / 1024.0 > 1 AND @FreeSize / 1024.0 <= 2 SET @EmailHead = '数据库磁盘容量告警(告警级别3)' ELSE IF @FreeSize / 1024.0 >= 0.5 AND @FreeSize / 1024.0 <= 1 SET @EmailHead = '数据库磁盘容量告警(告警级别4)' ELSE SET @EmailHead = '数据库磁盘容量告警(告警级别5)' SET @HtmlContent = N'' + N'' + @EmailHead + '' + N'' + CAST((SELECT td = DiskCD, '', td = STR(FreeSize * 1.0 / 1024, 6, 2), '' FROM #DiskCapacity FOR XML PATH('tr'), TYPE) AS NVARCHAR(MAX)) + N'磁盘盘符剩余空间(GB)' EXEC msdb.dbo.sp_send_dbmail @profile_name = 'DataBase_DDL_Event', @recipients = 'dba@yourcompany.com', @subject = '服务器磁盘空间告警', @body = @HtmlContent, @body_format = 'HTML' END DROP TABLE #DiskCapacityENDGO-- 使用示例:剩余空间低于5GB时告警EXEC sp_diskcapacity_alert3 @DiskCapacity = 5
在使用上述存储过程前,需要先配置数据库邮件:
-- 1. 启用数据库邮件功能EXEC sp_configure 'Database Mail XPs', 1RECONFIGURE-- 2. 创建邮件配置文件(手动在SSMS中配置更方便)-- SSMS → 管理 → 数据库邮件 → 配置向导-- 3. 测试邮件发送EXEC msdb.dbo.sp_send_dbmail @profile_name = 'DataBase_DDL_Event', @recipients = 'test@yourcompany.com', @subject = '测试邮件', @body = '磁盘监控已配置成功'
-- 创建作业(每天凌晨2点执行)USE msdbGOEXEC dbo.sp_add_job @job_name = N'磁盘空间监控告警'EXEC dbo.sp_add_jobstep @job_name = N'磁盘空间监控告警', @step_name = N'检查磁盘空间', @command = N'EXEC sp_diskcapacity_alert1 @Threshold = 20'EXEC dbo.sp_add_schedule @schedule_name = N'每天凌晨2点', @freq_type = 4, @freq_interval = 1, @active_start_time = 20000 -- 凌晨2点EXEC dbo.sp_attach_schedule @job_name = N'磁盘空间监控告警', @schedule_name = N'每天凌晨2点'EXEC dbo.sp_add_jobserver @job_name = N'磁盘空间监控告警'
临时开启用完关闭:方案一和方案二都采用了临时开启、用完关闭的方式
内网使用:这些功能建议仅在可信内网使用
最小权限:为监控账号分配最小必要权限
收到邮件内容如下:
一句话:三种方案任你选,配置好作业和邮件,磁盘监控全自动!
阅读原文:原文链接