Inleiding
Het is belangrijk voor een databasebeheerder om te weten wanneer er geen ruimte op een schijf is. Het is dus beter om het proces te automatiseren, zodat ze het niet handmatig op elke server hoeven te doen.
In dit artikel ga ik beschrijven hoe u automatische dagelijkse gegevensverzameling over logische stations en databasebestanden implementeert.
Oplossing
Algoritme:
1. Maak tabellen met gegevensopslag:
1.1. voor databasebestanden:
USE [DATABASE_NAME]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [srv].[DBFile](
[DBFile_GUID] [uniqueidentifier] ROWGUIDCOL NOT NULL,
[Server] [nvarchar](255) NOT NULL,
[Name] [nvarchar](255) NOT NULL,
[Drive] [nvarchar](10) NOT NULL,
[Physical_Name] [nvarchar](255) NOT NULL,
[Ext] [nvarchar](255) NOT NULL,
[Growth] [int] NOT NULL,
[IsPercentGrowth] [int] NOT NULL,
[DB_ID] [int] NOT NULL,
[DB_Name] [nvarchar](255) NOT NULL,
[SizeMb] [float] NOT NULL,
[DiffSizeMb] [float] NOT NULL,
[InsertUTCDate] [datetime] NOT NULL,
[UpdateUTCdate] [datetime] NOT NULL,
[File_ID] [int] NOT NULL,
CONSTRAINT [PK_DBFile] PRIMARY KEY CLUSTERED
(
[DBFile_GUID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [srv].[DBFile] ADD CONSTRAINT [DF_DBFile_DBFile_GUID]
DEFAULT (newid()) FOR [DBFile_GUID]
GO
ALTER TABLE [srv].[DBFile] ADD CONSTRAINT [DF_DBFile_InsertUTCDate]
DEFAULT (getutcdate()) FOR [InsertUTCDate]
GO
ALTER TABLE [srv].[DBFile] ADD CONSTRAINT [DF_DBFile_UpdateUTCdate]
DEFAULT (getutcdate()) FOR [UpdateUTCdate]
GO 1.2. voor logische schijven:
USE [DATABASE_NAME]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [srv].[Drivers](
[Driver_GUID] [uniqueidentifier] ROWGUIDCOL NOT NULL,
[Server] [nvarchar](255) NOT NULL,
[Name] [nvarchar](8) NOT NULL,
[TotalSpace] [float] NOT NULL,
[FreeSpace] [float] NOT NULL,
[DiffFreeSpace] [float] NOT NULL,
[InsertUTCDate] [datetime] NOT NULL,
[UpdateUTCdate] [datetime] NOT NULL,
CONSTRAINT [PK_Drivers] PRIMARY KEY CLUSTERED
(
[Driver_GUID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [srv].[Drivers] ADD CONSTRAINT [DF_Drivers_Driver_GUID]
DEFAULT (newid()) FOR [Driver_GUID]
GO
ALTER TABLE [srv].[Drivers] ADD CONSTRAINT [DF_Drivers_Server]
DEFAULT (@@servername) FOR [Server]
GO
ALTER TABLE [srv].[Drivers] ADD CONSTRAINT [DF_Drivers_TotalSpace]
DEFAULT ((0)) FOR [TotalSpace]
GO
ALTER TABLE [srv].[Drivers] ADD CONSTRAINT [DF_Drivers_FreeSpace]
DEFAULT ((0)) FOR [FreeSpace]
GO
ALTER TABLE [srv].[Drivers] ADD CONSTRAINT [DF_Drivers_DiffFreeSpace]
DEFAULT ((0)) FOR [DiffFreeSpace]
GO
ALTER TABLE [srv].[Drivers] ADD CONSTRAINT [DF_Drivers_InsertUTCDate]
DEFAULT (getutcdate()) FOR [InsertUTCDate]
GO
ALTER TABLE [srv].[Drivers] ADD CONSTRAINT [DF_Drivers_UpdateUTCdate]
DEFAULT (getutcdate()) FOR [UpdateUTCdate]
GO
Daarnaast moet u vooraf op de volgende manier een tabel met logische stations invullen:
Servernaam – volumelabel
2. creëer een noodzakelijke weergave voor het verzamelen van gegevens over databasebestanden:
USE [DATABASE_NAME]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE view [inf].[ServerDBFileInfo] as
SELECT @@Servername AS Server ,
File_id ,--file_id in a database. Its main value always equals 1
Type_desc ,--description of a file type
Name as [FileName] ,--logic file name in a database
LEFT(Physical_Name, 1) AS Drive ,--volume label where a database file is located
Physical_Name ,--a full name of a file in the operating system
RIGHT(physical_name, 3) AS Ext ,--file extension
Size as CountPage, --current file size in pages of 8 Kb
round((cast(Size*8 as float))/1024,3) as SizeMb, --file size in Mb
Growth, --growth
is_percent_growth, --growth in %
database_id,
DB_Name(database_id) as [DB_Name]
FROM sys.master_files--database_files
GO Hier wordt de systeemweergave sys.master_files gebruikt.
3. Maak een opgeslagen procedure die informatie retourneert op een logische schijf:
USE [DATABASE_NAME]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create procedure [srv].[sp_DriveSpace]
@DrivePath varchar(1024) --device (it is possible to set a volume label 'C:')
, @TotalSpace float output --total volume in bytes
, @FreeSpace float output --free disk space in bytes
as
begin
DECLARE @fso int
, @Drive int
, @DriveName varchar(255)
, @Folder int
, @Drives int
, @source varchar(255)
, @desc varchar(255)
, @ret int
, @Object int
-- Create an object of a file system
exec @ret = sp_OACreate 'Scripting.FileSystemObject', @fso output
set @Object = @fso
if @ret != 0
goto ErrorInfo
-- Get a folder on the specified path
exec @ret = sp_OAmethod @fso, 'GetFolder', @Folder output, @DrivePath
set @Object = @fso
if @ret != 0
goto ErrorInfo
-- Get a device
exec @ret = sp_OAmethod @Folder, 'Drive', @Drive output
set @Object = @Folder
if @ret != 0
goto ErrorInfo
-- Determine the whole device storage space
exec @ret = sp_OAGetProperty @Drive, 'TotalSize', @TotalSpace output
set @Object = @Drive
if @ret != 0
goto ErrorInfo
-- Determine a free space on a disk
exec @ret = sp_OAGetProperty @Drive, 'AvailableSpace', @FreeSpace output
set @Object = @Drive
if @ret != 0
goto ErrorInfo
DestroyObjects:
if @Folder is not null
exec sp_OADestroy @Folder
if @Drive is not null
exec sp_OADestroy @Drive
if @fso is not null
exec sp_OADestroy @fso
return (@ret)
ErrorInfo:
exec sp_OAGetErrorInfo @Object, @source output, @desc output
print 'Source error: ' + isnull( @source, 'n/a' ) + char(13) + 'Description: ' + isnull( @desc, 'n/a' )
goto DestroyObjects;
end
GO Raadpleeg het volgende artikel voor gedetailleerde informatie over deze procedure:Schijfruimte in T-SQL.
4. Maak een opgeslagen procedure voor het verzamelen van gegevens:
4.1. voor databasebestanden:
USE [DATABASE_NAME]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [srv].[MergeDBFileInfo]
AS
BEGIN
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
;merge [srv].[DBFile] as f
using [inf].[ServerDBFileInfo] as ff
on f.File_ID=ff.File_ID and f.DB_ID=ff.[database_id] and f.[Server]=ff.[Server]
when matched then
update set UpdateUTcDate = getUTCDate()
,[Name] = ff.[FileName]
,[Drive] = ff.[Drive]
,[Physical_Name] = ff.[Physical_Name]
,[Ext] = ff.[Ext]
,[Growth] = ff.[Growth]
,[IsPercentGrowth] = ff.[is_percent_growth]
,[SizeMb] = ff.[SizeMb]
,[DiffSizeMb] = round(ff.[SizeMb]-f.[SizeMb],3)
when not matched by target then
insert (
[Server]
,[Name]
,[Drive]
,[Physical_Name]
,[Ext]
,[Growth]
,[IsPercentGrowth]
,[DB_ID]
,[DB_Name]
,[SizeMb]
,[File_ID]
,[DiffSizeMb]
)
values (
ff.[Server]
,ff.[FileName]
,ff.[Drive]
,ff.[Physical_Name]
,ff.[Ext]
,ff.[Growth]
,ff.[is_percent_growth]
,ff.[database_id]
,ff.[DB_Name]
,ff.[SizeMb]
,ff.[File_id]
,0
)
when not matched by source and f.[Server]example@sqldat.com@SERVERNAME then delete;
END
GO 4.2. voor logische schijven:
USE [DATABASE_NAME]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [srv].[MergeDriverInfo]
AS
BEGIN
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
declare @Drivers table (
[Server] nvarchar(255),
Name nvarchar(8),
TotalSpace float,
FreeSpace float,
DiffFreeSpace float NULL
);
insert into @Drivers (
[Server],
Name,
TotalSpace,
FreeSpace
)
select [Server],
Name,
TotalSpace,
FreeSpace
from srv.Drivers
where [Server]example@sqldat.com@SERVERNAME;
declare @TotalSpace float;
declare @FreeSpace float;
declare @DrivePath nvarchar(8);
while(exists(select top(1) 1 from @Drivers where DiffFreeSpace is null))
begin
select top(1)
@DrivePath=Name
from @Drivers
where DiffFreeSpace is null;
exec srv.sp_DriveSpace @DrivePath = @DrivePath
, @TotalSpace = @TotalSpace out
, @FreeSpace = @FreeSpace out;
update @Drivers
set example@sqldat.com
,example@sqldat.com
,DiffFreeSpace=case when FreeSpace>0 then round(example@sqldat.com,3) else 0 end
where example@sqldat.com;
end
;merge [srv].[Drivers] as d
using @Drivers as dd
on d.Name=dd.Name and d.[Server]=dd.[Server]
when matched then
update set UpdateUTcDate = getUTCDate()
,[TotalSpace] = dd.[TotalSpace]
,[FreeSpace] = dd.[FreeSpace]
,[DiffFreeSpace]= dd.[DiffFreeSpace];
END
GO 5. Maak weergaven voor gegevensuitvoer:
5.1. voor databasebestanden:
USE [DATABASE_NAME]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create view [srv].[vDBFiles] as
SELECT [DBFile_GUID]
,[Server]
,[Name]
,[Drive]
,[Physical_Name]
,[Ext]
,[Growth]
,[IsPercentGrowth]
,[DB_ID]
,[File_ID]
,[DB_Name]
,[SizeMb]
,[DiffSizeMb]
,round([SizeMb]/1024,3) as [SizeGb]
,round([DiffSizeMb]/1024,3) as [DiffSizeGb]
,round([SizeMb]/1024/1024,3) as [SizeTb]
,round([DiffSizeMb]/1024/1024,3) as [DiffSizeTb]
,round([DiffSizeMb]/([SizeMb]/100), 3) as [DiffSizePercent]
,[InsertUTCDate]
,[UpdateUTCdate]
FROM [srv].[DBFile];
GO 5.2. voor logische schijven:
USE [DATABASE_NAME]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create view [srv].[vDrivers] as
select
[Driver_GUID]
,[Server]
,[Name]
,[TotalSpace] as [TotalSpaceByte]
,[FreeSpace] as [FreeSpaceByte]
,[DiffFreeSpace] as [DiffFreeSpaceByte]
,round([TotalSpace]/1024, 3) as [TotalSpaceKb]
,round([FreeSpace]/1024, 3) as [FreeSpaceKb]
,round([DiffFreeSpace]/1024, 3) as [DiffFreeSpaceKb]
,round([TotalSpace]/1024/1024, 3) as [TotalSpaceMb]
,round([FreeSpace]/1024/1024, 3) as [FreeSpaceMb]
,round([DiffFreeSpace]/1024/1024, 3) as [DiffFreeSpaceMb]
,round([TotalSpace]/1024/1024/1024, 3) as [TotalSpaceGb]
,round([FreeSpace]/1024/1024/1024, 3) as [FreeSpaceGb]
,round([DiffFreeSpace]/1024/1024/1024, 3) as [DiffFreeSpaceGb]
,round([TotalSpace]/1024/1024/1024/1024, 3) as [TotalSpaceTb]
,round([FreeSpace]/1024/1024/1024/1024, 3) as [FreeSpaceTb]
,round([DiffFreeSpace]/1024/1024/1024/1024, 3) as [DiffFreeSpaceTb]
,round([FreeSpace]/([TotalSpace]/100), 3) as [FreeSpacePercent]
,round([DiffFreeSpace]/([TotalSpace]/100), 3) as [DiffFreeSpacePercent]
,[InsertUTCDate]
,[UpdateUTCdate]
FROM [srv].[Drivers]
GO 6. Maak een taak in de SQL Server Agent en voer deze eenmaal per dag uit:
USE [DATABASE_NAME]; GO exec srv.MergeDBFileInfo; exec srv.MergeDriverInfo;
7. Verzamel alle gegevensuitvoer van servers. U kunt dit bijvoorbeeld doen met de SQL Server Agent.
8. Maak een opgeslagen procedure voor het genereren van een rapport en het verzenden naar beheerders. Aangezien het mogelijk is om het op verschillende manieren te implementeren, zal ik het in dit specifieke voorbeeld beschouwen:
USE [DATABASE_NAME]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [srv].[GetHTMLTableShortInfoDrivers]
@body nvarchar(max) OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
declare @tbl table (
Driver_GUID uniqueidentifier
,[Name] nvarchar(255)
,[TotalSpaceGb] float
,[FreeSpaceGb] float
,[DiffFreeSpaceMb] float
,[FreeSpacePercent] float
,[DiffFreeSpacePercent] float
,UpdateUTCDate datetime
,[Server] nvarchar(255)
,ID int identity(1,1)
);
declare
@Driver_GUID uniqueidentifier
,@Name nvarchar(255)
,@TotalSpaceGb float
,@FreeSpaceGb float
,@DiffFreeSpaceMb float
,@FreeSpacePercent float
,@DiffFreeSpacePercent float
,@UpdateUTCDate datetime
,@Server nvarchar(255)
,@ID int;
insert into @tbl(
Driver_GUID
,[Name]
,[TotalSpaceGb]
,[FreeSpaceGb]
,[DiffFreeSpaceMb]
,[FreeSpacePercent]
,[DiffFreeSpacePercent]
,UpdateUTCDate
,[Server]
)
select Driver_GUID
,[Name]
,[TotalSpaceGb]
,[FreeSpaceGb]
,[DiffFreeSpaceMb]
,[FreeSpacePercent]
,[DiffFreeSpacePercent]
,UpdateUTCDate
,[Server]
from srv.vDrivers
where [DiffFreeSpacePercent]<=-5
or [FreeSpacePercent]<=15
order by [Server] asc, [Name] asc;
if(exists(select top(1) 1 from @tbl))
begin
set @body='When analyzing I have got the data storage devices that either have free disk space less than 15%, or free space decreases over 5% a day:<br><br>'+'<TABLE BORDER=5>';
set @example@sqldat.com+'<TR>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+'№ p/p';
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+'GUID';
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+'SEVER';
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+'TOM';
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+'VOLUME, GB.';
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+'FREE, GB.';
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+'FREE SPACE CHANGE, MB.';
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+'FREE, %';
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+'FREE SPACE CHANGE, %';
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+'UTC DETECTION TIME';
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'</TR>';
while((select top 1 1 from @tbl)>0)
begin
set @example@sqldat.com+'<TR>';
select top 1
@Driver_GUID = Driver_GUID
,@Name = Name
,@TotalSpaceGb = TotalSpaceGb
,@FreeSpaceGb = FreeSpaceGb
,@DiffFreeSpaceMb = DiffFreeSpaceMb
,@FreeSpacePercent = FreeSpacePercent
,@DiffFreeSpacePercent = DiffFreeSpacePercent
,@UpdateUTCDate = UpdateUTCDate
,@Server = [Server]
,@ID = [ID]
from @tbl;
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+cast(@ID as nvarchar(max));
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+cast(@Driver_GUID as nvarchar(255));
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+coalesce(@Server,'');
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+coalesce(@Name,'');
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+cast(@TotalSpaceGb as nvarchar(255));
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+cast(@FreeSpaceGb as nvarchar(255));
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+cast(@DiffFreeSpaceMb as nvarchar(255));
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+cast(@FreeSpacePercent as nvarchar(255));
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+cast(@DiffFreeSpacePercent as nvarchar(255));
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+rep.GetDateFormat(@UpdateUTCDate, default)+' '+rep.GetTimeFormat(@UpdateUTCDate, default);
set @example@sqldat.com+'</TD>';
delete from @tbl
where example@sqldat.com;
set @example@sqldat.com+'</TR>';
end
set @example@sqldat.com+'</TABLE>';
set @example@sqldat.com+'<br><br>';
To get the detailed information, refer to the view SRV.srv.vDrivers<br><br>
To view the information on database files, refer to the view DATABASE_NAME.srv.vDBFiles';
end
END
GO Deze opgeslagen procedure genereert een HTML-rapport over logische stations die ofwel minder dan 15% vrije schijfruimte hebben, ofwel met meer dan 5% per dag afnemen. De laatste vertoont een vreemde activiteit van records, wat betekent dat iemand heel vaak te veel informatie op deze schijf opslaat. Het kan om de volgende redenen gebeuren:
- Het is tijd om een schijf uit te breiden;
- Het is noodzakelijk om ongebruikte bestanden op een logische schijf te verwijderen;
- Wis en verklein logbestanden, evenals bestanden met informatie en andere tabellen.
Oplossing
In dit artikel heb ik een voorbeeld geanalyseerd van het implementeren van een systeem van dagelijkse automatische gegevensverzameling over lokale schijven en databasebestanden. Deze informatie maakt het mogelijk om van tevoren te achterhalen welke schijf minder vrije ruimte heeft en welke databasebestanden drastisch groeien. Het maakt het mogelijk om een geval te vermijden waarin er geen ruimte op een schijf is en om een reden te vinden waarom een proces veel ruimte op een schijf in beslag neemt.
Lees ook:
Automatische gegevensverzameling van wijzigingen in het databaseschema in MS SQL Server
Automatische gegevensverzameling over voltooide taken in MS SQL Server