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

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

Wprowadzenie

Ważne jest, aby administrator bazy danych wiedział, jakie zadania i jak zostały wykonane. Aby uprościć ten proces, lepiej go zautomatyzować, niż wykonywać ręcznie.

W tym artykule przeanalizuję na konkretnym przykładzie, jak automatycznie zbierać dane o wykonanych zadaniach agenta SQL Server.

Rozwiązanie

Algorytm:

  1. Utwórz instancję, aby wybrać zadania:
    USE [DATABASE_NAME]
    GO
    
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE view [srv].[vJobRunShortInfo] as
    SELECT sj.[job_id] as Job_GUID
          ,j.name as Job_Name
          ,case sj.[last_run_outcome]
            when 0 then 'Error'
            when 1 then 'Successful'
            when 3 then 'Canceled'
            else case when sj.[last_run_date] is not null and len(sj.[last_run_date])=8 then 'Inconsistent state'
                    else NULL
                    end
           end as LastFinishRunState
          ,sj.[last_run_outcome] as LastRunOutcome
          ,case when sj.[last_run_date] is not null and len(sj.[last_run_date])=8 then
            DATETIMEFROMPARTS(
            substring(cast(sj.[last_run_date] as nvarchar(255)),1,4),
            substring(cast(sj.[last_run_date] as nvarchar(255)),5,2),
            substring(cast(sj.[last_run_date] as nvarchar(255)),7,2),
            case when len(cast(sj.[last_run_time] as nvarchar(255)))>=5 
            then substring(cast(sj.[last_run_time] as nvarchar(255)),1,len(cast(sj.[last_run_time] as nvarchar(255)))-4)
              else 0
              end,
            case when len(right(cast(sj.[last_run_time] as nvarchar(255)),4))>=4 
            then substring(right(cast(sj.[last_run_time] as nvarchar(255)),4),1,2)
            when len(right(cast(sj.[last_run_time] as nvarchar(255)),4))=3  
            then substring(right(cast(sj.[last_run_time] as nvarchar(255)),4),1,1)
               else 0
               end,
            right(cast(sj.[last_run_duration] as nvarchar(255)),2),
                                0
                            )
           else NULL
           end as LastDateTime
           ,case when len(cast(sj.[last_run_duration] as nvarchar(255)))>5 
           then substring(cast(sj.[last_run_duration] as nvarchar(255)),1,len(cast(sj.[last_run_duration] as nvarchar(255)))-4)
                when len(cast(sj.[last_run_duration] as nvarchar(255)))=5 
           then '0'+substring(cast(sj.[last_run_duration] as nvarchar(255)),1,len(cast(sj.[last_run_duration] as nvarchar(255)))-4)
                else '00'
           end
           +':'
           +case when len(cast(sj.[last_run_duration] as nvarchar(255)))>=4 then substring(right(cast(sj.[last_run_duration] as nvarchar(255)),4),1,2)
                 when len(cast(sj.[last_run_duration] as nvarchar(255)))=3  then '0'+substring(right(cast(sj.[last_run_duration] as nvarchar(255)),4),1,1)
                 else '00'
           end
           +':'
           +case when len(cast(sj.[last_run_duration] as nvarchar(255)))>=2
            then substring(right(cast(sj.[last_run_duration] as nvarchar(255)),2),1,2)
                 when len(cast(sj.[last_run_duration] as nvarchar(255)))=2  
            then '0'+substring(right(cast(sj.[last_run_duration] as nvarchar(255)),2),1,1)
                 else '00'
           end as [LastRunDurationString]
          ,sj.last_run_duration as LastRunDurationInt
          ,sj.[last_outcome_message] as LastOutcomeMessage
          ,j.enabled as [Enabled]
      FROM [msdb].[dbo].[sysjobservers] as sj
      inner join msdb.dbo.sysjobs_view as j on j.job_id=sj.job_id;
    
    GO

    Aby to zrobić, użyj instancji sysjobservers i sysjobs_view.

  2. Utwórz tabelę do przechowywania wybranych danych:
    USE [DATABASE_NAME]
    GO
    
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE TABLE [srv].[ShortInfoRunJobs](
        [Job_GUID] [uniqueidentifier] NOT NULL,
        [Job_Name] [nvarchar](255) NOT NULL,
        [LastFinishRunState] [nvarchar](255) NULL,
        [LastDateTime] [datetime] NOT NULL,
        [LastRunDurationString] [nvarchar](255) NULL,
        [LastRunDurationInt] [int] NULL,
        [LastOutcomeMessage] [nvarchar](255) NULL,
        [LastRunOutcome] [tinyint] NOT NULL,
        [Server] [nvarchar](255) NOT NULL,
        [InsertUTCDate] [datetime] NOT NULL,
        [ID] [int] IDENTITY(1,1) NOT NULL,
     CONSTRAINT [PK_ShortInfoRunJobs] PRIMARY KEY CLUSTERED 
    (
        [ID] 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].[ShortInfoRunJobs] ADD  CONSTRAINT [DF_ShortInfoRunJobs_InsertUTCDate]  DEFAULT (getutcdate()) FOR [InsertUTCDate]
    GO
  3. Utwórz zadanie w programie SQL Server Agent i uzyskaj informacje o zadaniach, które zostały wykonane przez długi czas (ponad 30 sekund) lub nie zostały ukończone. Musisz zebrać te informacje przez ostatnie dwa dni:
    USE [DATABASE_NAME];
    GO
    
    truncate table [srv].[ShortInfoRunJobs];
    
    INSERT INTO [srv].[ShortInfoRunJobs]
               ([Job_GUID]
               ,[Job_Name]
               ,[LastFinishRunState]
               ,[LastDateTime]
               ,[LastRunDurationString]
               ,[LastRunDurationInt]
               ,[LastOutcomeMessage]
               ,[LastRunOutcome]
               ,[Server])
        SELECT [Job_GUID]
              ,[Job_Name]
              ,[LastFinishRunState]
              ,[LastDateTime]
              ,[LastRunDurationString]
              ,[LastRunDurationInt]
              ,[LastOutcomeMessage]
              ,LastRunOutcome
              ,@@SERVERNAME
          FROM [srv].[vJobRunShortInfo]
          where [Enabled]=1
          and ([LastRunOutcome]=0
          or [LastRunDurationInt]>=30)
          and LastDateTime>=DateAdd(day,-2,getdate());
    GO

    Tutaj możesz ustawić filtr, aby usunąć wszystkie niepotrzebne zadania. Na przykład te zadania, które odnoszą się do replikacji, ponieważ ich ukończenie zajmuje znacznie więcej czasu.

Wygeneruj raport HTML, aby wysłać go na adres e-mail administratorów:

USE [DATABASE_NAME]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [srv].[GetHTMLTableShortInfoRunJobs]
    @body nvarchar(max) OUTPUT
AS
BEGIN
    /*
        generates an HTML-code for the tables of completed tasks
    */
    SET NOCOUNT ON;
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

    declare @tbl table (
                        Job_GUID                uniqueidentifier
                        ,Job_Name               nvarchar(255)
                        ,LastFinishRunState     nvarchar(255)
                        ,LastDateTime           datetime
                        ,LastRunDurationString  nvarchar(255)
                        ,LastOutcomeMessage     nvarchar(max)
                        ,[Server]               nvarchar(255)
                        ,ID                     int identity(1,1)
                       );

    declare
    @Job_GUID               uniqueidentifier
    ,@Job_Name              nvarchar(255)
    ,@LastFinishRunState    nvarchar(255)
    ,@LastDateTime          datetime
    ,@LastRunDurationString nvarchar(255)
    ,@LastOutcomeMessage    nvarchar(max)
    ,@Server                nvarchar(255)
    ,@ID                    int;

    insert into @tbl(
                        Job_GUID
                        ,Job_Name
                        ,LastFinishRunState
                        ,LastDateTime
                        ,LastRunDurationString
                        ,LastOutcomeMessage
                        ,[Server]
                    )
            select      Job_GUID
                        ,Job_Name
                        ,LastFinishRunState
                        ,LastDateTime
                        ,LastRunDurationString
                        ,LastOutcomeMessage
                        ,[Server]
            from    srv.ShortInfoRunJobs
            --order by LastRunDurationInt desc;

    if(exists(select top(1) 1 from @tbl))
    begin
        set @body='When analyzing these tasks execution, I have found out the tasks that either have failed with an error,
        or, it has taken more than 30 seconds for their execution :<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]+'TASK';
        set @[email protected]+'</TD>';

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

        set @[email protected]+'<TD>';
        set @[email protected]+'DATE AND TIME';
        set @[email protected]+'</TD>';

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

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

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

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

        while((select top 1 1 from @tbl)>0)
        begin
            set @[email protected]+'<TR>';

            select top 1
            @ID                     =   [ID]
            ,@Job_GUID              =   Job_GUID
            ,@Job_Name              =   Job_Name                
            ,@LastFinishRunState    =   LastFinishRunState      
            ,@LastDateTime          =   LastDateTime            
            ,@LastRunDurationString =   LastRunDurationString   
            ,@LastOutcomeMessage    =   LastOutcomeMessage      
            ,@Server                =   [Server]                
            from @tbl
            order by LastRunDurationInt desc;

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

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

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

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

            set @[email protected]+'<TD>';
            set @[email protected]+rep.GetDateFormat(@LastDateTime, default)+' '+rep.GetTimeFormat(@LastDateTime, default);--cast(@InsertDate as nvarchar(max));
            set @[email protected]+'</TD>';

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

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

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

            delete from @tbl
            where [email protected];

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

        set @[email protected]+'</TABLE>';
    end
    else
    begin
        set @body='The tasks, that have failed with an error or that have been executed for more than 30 seconds, have not been found';
    end

    set @[email protected]+'<br><br>For the detailed information, please refer to the table DATABASE_NAME.srv.ShortInfoRunJobs';
END

GO

Ta procedura składowana generuje raport HTML o ukończonych zadaniach, które były wykonywane przez 30 sekund lub których nie udało się ukończyć.

Wynik

W tym artykule zbadałem na konkretnym przykładzie implementację codziennego automatycznego zbierania danych o wykonanych zadaniach w SQL Server Agent. Informacje te pomagają określić zadania, które były wykonywane przez długi czas lub zakończone z błędem. Umożliwia administratorowi podjęcie działań w celu uniknięcia takich błędów w przyszłości. Na przykład można przyspieszyć działanie zadania lub ustawić maksymalny czas dla określonego zadania.

To rozwiązanie pomaga również monitorować problemy związane z kopiami zapasowymi. Jednak omówimy to później, bo nie wystarczy powiadomić o ważnych zadaniach raz dziennie. Konieczne jest natychmiastowe i regularne wysyłanie wiadomości e-mail, dopóki błąd nie zostanie naprawiony.

Jeśli potrzebujesz wybrać dane z kilku serwerów, możliwe jest połączenie wyników i wysłanie ich `za pośrednictwem jednego e-maila.

Referencje:

» sysjobs
» sysjobservers

Dalsze czytanie:

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

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

Konfiguracja powiadomień o poczcie bazy danych 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. SQL Server SELECT, gdzie dowolna kolumna zawiera „x”

  2. Jak podzielić ciąg i wstawić wartości do tabeli w SQL Server

  3. Utwórz schemat UDF związany ze schematem w SQL Server

  4. Wyrażenia regularne na serwerach SQL Server?

  5. SQL DEFAULT Ograniczenie do wstawiania kolumny z wartością domyślną do tabeli SQL Server