Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Automatyczne zbieranie danych:Pliki bazy danych i dyski logiczne w MS SQL Server

Wprowadzenie

Ważne jest, aby administrator bazy danych wiedział, kiedy na dysku nie ma miejsca. Dlatego lepiej jest zautomatyzować proces, aby nie robili tego ręcznie na każdym serwerze.

W tym artykule opiszę, jak wdrożyć automatyczne codzienne zbieranie danych o dyskach logicznych i plikach baz danych.

Rozwiązanie

Algorytm:

1. Utwórz tabele przechowywania danych:
1.1. dla plików baz danych:

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. dla dysków logicznych:

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

Dodatkowo należy wcześniej wypełnić tabelę z dyskami logicznymi w następujący sposób:
Nazwa serwera – etykieta woluminu

2. utwórz niezbędny widok do zbierania danych o plikach baz danych:

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

Tutaj używany jest widok systemowy sys.master_files.

3. Utwórz procedurę składowaną, która zwraca informacje na dysku logicznym:

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

Aby uzyskać szczegółowe informacje na temat tej procedury, zapoznaj się z następującym artykułem:Miejsce na dysku w T-SQL.

4. Utwórz procedurę składowaną do gromadzenia danych:

4.1. dla plików baz danych:

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][email protected]@SERVERNAME then delete;
END

GO

4.2. dla dysków logicznych:

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][email protected]@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 [email protected]
           ,[email protected]
           ,DiffFreeSpace=case when FreeSpace>0 then round([email protected],3) else 0 end
        where [email protected];
    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. Utwórz widoki danych wyjściowych:

5.1. dla plików baz danych:

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. dla dysków logicznych:

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. Utwórz zadanie w agencie serwera SQL i uruchamiaj je raz dziennie:

USE [DATABASE_NAME];
GO

exec srv.MergeDBFileInfo;
exec srv.MergeDriverInfo;

7. Zbierz wszystkie dane wyjściowe z serwerów. Możesz to zrobić na przykład za pomocą SQL Server Agent.

8. Utwórz procedurę składowaną do generowania raportu i wysyłania go do administratorów. Ponieważ możliwe jest zaimplementowanie go na różne sposoby, rozważę to na tym konkretnym przykładzie:

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 @[email protected]+'<TR>';

        set @[email protected]+'<TD>';
        set @[email protected]+'№ p/p';
        set @[email protected]+'</TD>';

        set @[email protected]+'<TD>';
        set @[email protected]+'GUID';
        set @[email protected]+'</TD>';

        set @[email protected]+'<TD>';
        set @[email protected]+'SEVER';
        set @[email protected]+'</TD>';

        set @[email protected]+'<TD>';
        set @[email protected]+'TOM';
        set @[email protected]+'</TD>';

        set @[email protected]+'<TD>';
        set @[email protected]+'VOLUME, GB.';
        set @[email protected]+'</TD>';

        set @[email protected]+'<TD>';
        set @[email protected]+'FREE, GB.';
        set @[email protected]+'</TD>';

        set @[email protected]+'<TD>';
        set @[email protected]+'FREE SPACE CHANGE, MB.';
        set @[email protected]+'</TD>';

        set @[email protected]+'<TD>';
        set @[email protected]+'FREE, %';
        set @[email protected]+'</TD>';

        set @[email protected]+'<TD>';
        set @[email protected]+'FREE SPACE CHANGE, %';
        set @[email protected]+'</TD>';

        set @[email protected]+'<TD>';
        set @[email protected]+'UTC DETECTION TIME';
        set @[email protected]+'</TD>';

        set @[email protected]+'</TR>';

        while((select top 1 1 from @tbl)>0)
        begin
            set @[email protected]+'<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 @[email protected]+'<TD>';
            set @[email protected]+cast(@ID as nvarchar(max));
            set @[email protected]+'</TD>';

            set @[email protected]+'<TD>';
            set @[email protected]+cast(@Driver_GUID as nvarchar(255));
            set @[email protected]+'</TD>';

            set @[email protected]+'<TD>';
            set @[email protected]+coalesce(@Server,'');
            set @[email protected]+'</TD>';

            set @[email protected]+'<TD>';
            set @[email protected]+coalesce(@Name,'');
            set @[email protected]+'</TD>';

            set @[email protected]+'<TD>';
            set @[email protected]+cast(@TotalSpaceGb as nvarchar(255));
            set @[email protected]+'</TD>';

            set @[email protected]+'<TD>';
            set @[email protected]+cast(@FreeSpaceGb as nvarchar(255));
            set @[email protected]+'</TD>';

            set @[email protected]+'<TD>';
            set @[email protected]+cast(@DiffFreeSpaceMb as nvarchar(255));
            set @[email protected]+'</TD>';

            set @[email protected]+'<TD>';
            set @[email protected]+cast(@FreeSpacePercent as nvarchar(255));
            set @[email protected]+'</TD>';

            set @[email protected]+'<TD>';
            set @[email protected]+cast(@DiffFreeSpacePercent as nvarchar(255));
            set @[email protected]+'</TD>';

            set @[email protected]+'<TD>';
            set @[email protected]+rep.GetDateFormat(@UpdateUTCDate, default)+' '+rep.GetTimeFormat(@UpdateUTCDate, default);
            set @[email protected]+'</TD>';

            delete from @tbl
            where [email protected];

            set @[email protected]+'</TR>';
        end

        set @[email protected]+'</TABLE>';

        set @[email protected]+'<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

Ta procedura składowana generuje raport HTML dotyczący dysków logicznych, które mają mniej niż 15% wolnego miejsca lub zmniejszają się o ponad 5% dziennie. Ten ostatni pokazuje dziwną aktywność rekordów, co oznacza, że ​​ktoś bardzo często przechowuje na tym dysku zbyt wiele informacji. Może się to zdarzyć z następujących powodów:

  1. Czas na rozszerzenie dysku;
  2. Konieczne jest usunięcie nieużywanych plików na dysku logicznym;
  3. Usuń i zmniejsz pliki dziennika, a także pliki informacji i inne tabele.

Rozwiązanie

W tym artykule przeanalizowałem przykład wdrożenia systemu codziennego automatycznego zbierania danych o dyskach lokalnych i plikach baz danych. Informacje te pozwalają z wyprzedzeniem dowiedzieć się, który dysk ma mniej wolnego miejsca, a także jakie pliki bazy danych drastycznie się rozrastają. Pozwala to uniknąć sytuacji, gdy na dysku nie ma miejsca i dowiedzieć się, dlaczego proces zajmuje dużo miejsca na dysku.

Przeczytaj także:

Automatyczne zbieranie danych o zmianach schematu bazy danych w MS SQL Server

Automatyczne zbieranie danych o zakończonych zadaniach w MS SQL Server


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Czy istnieje sposób na uzyskanie listy wszystkich aktualnych tabel tymczasowych w SQL Server?

  2. Badanie opcji oczekiwania na blokadę o niskim priorytecie w programie SQL Server 2014 CTP1

  3. Sposoby migracji bazy danych SQL Server do Azure SQL Database

  4. Dowiedz się, czy ograniczenie CHECK jest na poziomie kolumny czy na poziomie tabeli w programie SQL Server (przykłady T-SQL)

  5. STRING_SPLIT() w SQL Server 2016:kontynuacja nr 2