SQL Server--獲取磁盤空間使用狀況

對於DBA來講,監控磁盤使用狀況是必要的工做,而後沒有比較簡單的方法能獲取到磁盤空間使用率信息,下面總結下這些年攢下的腳本:sql

最經常使用的查看磁盤剩餘空間,這個屬於DBA入門必記的東西:shell

-- 查看磁盤可用空間
EXEC master.dbo.xp_fixeddrives

xp_fixeddrives方式有點是系統自帶,可直接使用,缺點是不能查看磁盤總大小和不能查看SQL Server未使用到的磁盤信息數據庫

==============================================================運維

使用sys.dm_os_volume_stats函數ide

--======================================================================
--查看數據庫文件使用的磁盤空間使用狀況
WITH T1 AS (
SELECT DISTINCT
REPLACE(vs.volume_mount_point,':\','') AS Drive_Name ,
CAST(vs.total_bytes / 1024.0 / 1024 / 1024 AS NUMERIC(18,2)) AS Total_Space_GB ,
CAST(vs.available_bytes / 1024.0 / 1024 / 1024  AS NUMERIC(18,2)) AS Free_Space_GB
FROM    sys.master_files AS f
CROSS APPLY sys.dm_os_volume_stats(f.database_id, f.file_id) AS vs
)
SELECT
Drive_Name,
Total_Space_GB,
Total_Space_GB-Free_Space_GB AS Used_Space_GB,
Free_Space_GB,
CAST(Free_Space_GB*100/Total_Space_GB AS NUMERIC(18,2)) AS Free_Space_Percent
FROM T1

查詢效果:函數

sys.dm_os_volume_stats函數很好用,能直接查詢到總空間和空閒空間,惋惜只支持SQL Server 2008 R2 SP1即更高版本,另外沒法查到數據庫文件未使用到的磁盤sqlserver

==============================================================測試

爲兼容低版本,可採用xp_fixeddrives+xp_cmdshell方式來獲取,我寫了幾個存儲過程來獲取磁盤信息:google

USE [monitor]
GO

/****** Object:  StoredProcedure [dbo].[usp_get_disk_free_size]    Script Date: 2016/5/25 18:21:11 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO


-- =============================================
-- Author:        GGA
-- Create date:    2016-2-1
-- Description:    收集磁盤剩餘空間信息
-- =============================================
CREATE PROCEDURE [dbo].[usp_get_disk_free_size]
AS
BEGIN
    SET NOCOUNT ON;
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

--==========================================
--建立相關表

IF OBJECT_ID('server_disk_usage') IS NULL
BEGIN
    CREATE TABLE [dbo].[server_disk_usage](
        [disk_num] [nvarchar](10) NOT NULL,
        [total_size_mb] [bigint] NOT NULL CONSTRAINT [DF_server_disk_usage_total_size_mb]  DEFAULT ((0)),
        [free_siez_mb] [bigint] NOT NULL CONSTRAINT [DF_server_disk_usage_free_siez_mb]  DEFAULT ((0)),
        [disk_info] [nvarchar](400) NOT NULL CONSTRAINT [DF_server_disk_usage_disk_info]  DEFAULT (''),
        [check_time] [datetime] NOT NULL CONSTRAINT [DF_server_disk_usage_check_time]  DEFAULT (getdate()),
         CONSTRAINT [PK_server_disk_usage] PRIMARY KEY CLUSTERED 
        (
            [disk_num] ASC
        )
    ) ON [PRIMARY]
END


--==========================================
--查看全部數據庫使用到的磁盤剩餘空間
DECLARE @disk TABLE(
        [disk_num] VARCHAR(50),
        [free_siez_mb] INT)
INSERT INTO @disk
EXEC xp_fixeddrives

--更新當前磁盤的剩餘空間信息
UPDATE M
SET M.[free_siez_mb]=D.[free_siez_mb]
FROM [dbo].[server_disk_usage] AS M
INNER JOIN @disk AS D
ON M.[disk_num]=D.[disk_num]

--插入新增磁盤的剩餘空間信息
INSERT INTO [dbo].[server_disk_usage]
(
    [disk_num],
    [free_siez_mb]
)
SELECT 
[disk_num],
[free_siez_mb]
FROM @disk AS D
WHERE NOT EXISTS(
    SELECT 1
    FROM [dbo].[server_disk_usage] AS M 
    WHERE M.[disk_num]=D.[disk_num] )

END



GO

/****** Object:  StoredProcedure [dbo].[usp_get_disk_total_size]    Script Date: 2016/5/25 18:21:11 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO



-- =============================================
-- Author:        GGA
-- Create date:    2016-2-1
-- Description:    收集磁盤總空間信息
-- =============================================
CREATE PROCEDURE [dbo].[usp_get_disk_total_size]
AS
BEGIN
    SET NOCOUNT ON;
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
    
IF NOT EXISTS(SELECT * FROM [dbo].[server_disk_usage]
        WHERE [total_size_mb] = 0)
BEGIN
    RETURN;
END

--==========================================
--開啓CMDShell
EXEC sp_configure 'show advanced options',1;

RECONFIGURE WITH OVERRIDE;

EXEC sp_configure 'xp_cmdshell',1;

RECONFIGURE WITH OVERRIDE

--========================================
--建立臨時表用來存放每一個盤符的數據
CREATE TABLE #tempDisks
(
    ID INT IDENTITY(1,1),
    DiskSpace NVARCHAR(200)
)
--============================================
--將須要檢查的磁盤放入臨時表#checkDisks
SELECT 
ROW_NUMBER()OVER(ORDER BY [disk_num]) AS RID,
[disk_num]
INTO #checkDisks
FROM [dbo].[server_disk_usage] 
WHERE [total_size_mb] = 0;

--============================================
--循環臨時表#checkDisks檢查每一個磁盤的總量

DECLARE @disk_num NVARCHAR(20)
DECLARE @total_size_mb INT
DECLARE @sql NVARCHAR(200)
DECLARE @max INT
DECLARE @min INT
SELECT @max=MAX(RID),@min=MIN(RID) FROM #checkDisks

WHILE(@min<=@max)
BEGIN
SELECT @disk_num=[disk_num] 
FROM #checkDisks WHERE RID=@min

SET @sql = N'EXEC sys.xp_cmdshell ''fsutil volume diskfree '+@disk_num+':'+''''
PRINT @sql

INSERT INTO #tempDisks
EXEC sys.sp_executesql @sql

SELECT  @total_size_mb=CAST((RIGHT(DiskSpace,LEN(DiskSpace)
    -CHARINDEX(': ',DiskSpace)-1)) AS BIGINT)/1024/1024
FROM #tempDisks WHERE id = 2

SELECT @total_size_mb,@disk_num

UPDATE [dbo].[server_disk_usage]
SET [total_size_mb]=@total_size_mb
WHERE [disk_num]=@disk_num

--SELECT * FROM  #tempDisks

TRUNCATE TABLE #tempDisks

SET @min=@min+1

END


--==========================================
--CMDShell

EXEC sp_configure 'xp_cmdshell',0;

EXEC  sp_configure 'show advanced options',1;

RECONFIGURE WITH OVERRIDE;


END




GO

/****** Object:  StoredProcedure [dbo].[usp_get_disk_usage]    Script Date: 2016/5/25 18:21:11 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

-- =============================================
-- Author:        GGA
-- Create date:    2016-2-1
-- Description:    收集磁盤總空間信息
-- =============================================
CREATE PROCEDURE [dbo].[usp_get_disk_usage]
AS
BEGIN
    SET NOCOUNT ON;
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
    
    EXEC [dbo].[usp_get_disk_free_size]
    EXEC [dbo].[usp_get_disk_total_size]
    
    SELECT 
    [disk_num] AS Drive_Name
    ,CAST([total_size_mb]/1024.0 AS NUMERIC(18,2)) AS Total_Space_GB
    ,CAST(([total_size_mb]-[free_siez_mb])/1024.0 AS NUMERIC(18,2)) AS Used_Space_GB
    ,CAST([free_siez_mb]/1024.0 AS NUMERIC(18,2)) AS Free_Space_GB
    ,CAST([free_siez_mb]*100/[total_size_mb] AS NUMERIC(18,2)) AS Free_Space_Percent
    ,[disk_info]
    ,[check_time]
    FROM [monitor].[dbo].[server_disk_usage]

END
GO


--==================================
--查看磁盤空間使用
EXEC [dbo].[usp_get_disk_usage]
 

效果顯示:spa

只有第一次收集磁盤信息或第一次收集新磁盤信息時,纔會調用xp_cmdshell來獲取磁盤的總大小,儘可能減小xp_cmdshell開啓帶來的風險,可配合SQL Server Agent Job來使用,按期調用存儲過程刷新磁盤信息,監控程序直接訪問數據表來或許最後一次刷新時的磁盤信息。

此方式有一缺點是開啓xp_cmdshell後獲取磁盤總大小期間,其餘進程可能關閉xp_cmdshell,形成存儲過程執行失敗,雖然發生機率較低,但畢竟存在。

==============================================================

若是想跳過存儲過程+SQL Server Agent Job方式,直接經過程序來調用xp_cmdshell,當程序使用「RECONFIGURE WITH OVERRIDE」來配置時,會報以下錯誤:

CONFIG statement cannot be used inside a user transaction.DB-Lib error message 574

錯誤相似於咱們在SSMS中使用事務包裹sp_configure語句,如:

BEGIN TRAN
EXEC sp_configure 'show advanced options',1;
RECONFIGURE WITH OVERRIDE;
EXEC sp_configure 'xp_cmdshell',1;
RECONFIGURE WITH OVERRIDE;
COMMIT

錯誤消息爲:

配置選項 'show advanced options' 已從 0 更改成 1。請運行 RECONFIGURE 語句進行安裝。
消息 574,級別 16,狀態 0,第 3 行
在用戶事務內不能使用 CONFIG 語句。
配置選項 'xp_cmdshell' 已從 0 更改成 1。請運行 RECONFIGURE 語句進行安裝。
消息 574,級別 16,狀態 0,第 5 行
在用戶事務內不能使用 CONFIG 語句。

難道不能經過程序調用RECONFIGURE WITH OVERRIDE語句?

固然不是,google下相關錯誤,僅發現下面一個相關,有興趣的能夠參考下:

https://www.sqlservercentral.com/Forums/Topic1349778-146-1.aspx

粗略看了下,使用存儲過程套存儲過程的方式來繞過報錯,本人沒有具體測試,感受太繁瑣,因而採用簡單粗暴的方式,既然報「在用戶事務內不能使用 CONFIG 語句」,哪我是否能夠先COMMIT下幹掉「用戶事務」呢?

基於此思路,最終測試得到下面方式:

DECLARE @sql VARCHAR(2000)
SET @sql ='
COMMIT;
EXEC sp_configure ''show advanced options'',1;
RECONFIGURE WITH OVERRIDE;
EXEC sp_configure ''xp_cmdshell'',1;
RECONFIGURE WITH OVERRIDE;
'
EXEC(@sql)

仔細的朋友發現我先執行了COMMIT, 您沒看錯,這樣的打開方式雖然怪異但的確是一種打開方式,在SSMS中執行結果爲:

消息 3902,級別 16,狀態 1,第 2COMMIT TRANSACTION 請求沒有對應的 BEGIN TRANSACTION。
配置選項 'show advanced options' 已從 1 更改成 1。請運行 RECONFIGURE 語句進行安裝。
配置選項 'xp_cmdshell' 已從 1 更改成 1。請運行 RECONFIGURE 語句進行安裝。

雖然報錯,可是的可是,xp_cmdshell的值已經被設置爲1,即腳本執行生效啦!

將此代碼移植到代碼中,而後經過TRY CATCH將異常捕獲並丟棄,你就能夠愉快地調用xp_cmdshell啦。

==============================================================

使用xp_cmdshell開了頭,固然相關信息也可使用相似方式來獲取啦!

好比獲取磁盤的扇區信息:

--====================================
--使用xp_cmdshell來執行CMD命令
--獲取磁盤扇區信息
EXEC sp_configure 'show advanced options',1 
GO
RECONFIGURE
GO
sp_configure 'xp_cmdshell',1 
GO
RECONFIGURE
GO
EXEC xp_cmdshell 'fsutil fsinfo ntfsinfo D: | find "每一個"';
GO
sp_configure 'xp_cmdshell',0 
GO
RECONFIGURE
GO
sp_configure 'show advanced options', 0 
GO
RECONFIGURE
GO

運行效果爲:

固然你可使用fsutil fsinfo ntfsinfo D:來獲取完整信息,可是更值得您關注的就是上面這幾行。

==============================================================

感言:

當了這麼多年的SQL Server DBA,如今找份像樣的SQL SERVER DBA的工做真不容易,一方面是當前市場趨勢致使,另外一方面也是咱DBA本身「做死」形成的,看到不少同行包括我本身都還處在「刀耕火種」時代,有問題就在界面上點來點去,給外界一種「SQL Server很容易運維」的假象,而再看看MySQL DBA,只要你能僞裝「研究下源碼」,立馬給人一種「很牛逼」的趕腳,因而乎年薪三五十萬再也不是夢想!

智能運維的口號已經吹響,在轉MySQL的路上,仍時時不忘本身是個老SQL Server DBA。

==============================================================

蔣委員長的字,與諸君共勉!

相關文章
相關標籤/搜索