Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Automatische Datenerfassung über abgeschlossene Aufgaben in MS SQL Server

Einführung

Für einen Datenbankadministrator ist es wichtig zu wissen, welche Aufgaben und wie sie abgeschlossen wurden. Um diesen Prozess zu vereinfachen, ist es besser, ihn zu automatisieren, als ihn manuell durchzuführen.

In diesem Artikel werde ich an einem bestimmten Beispiel analysieren, wie automatisch Daten über abgeschlossene Aufgaben des SQL Server-Agenten gesammelt werden.

Lösung

Algorithmus:

  1. Erstellen Sie eine Instanz, um Aufgaben auszuwählen:
    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

    Verwenden Sie dazu die Instanzen sysjobservers und sysjobs_view.

  2. Erstellen Sie eine Tabelle zum Speichern ausgewählter Daten:
    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. Erstellen Sie eine Aufgabe im SQL Server Agent und erhalten Sie Informationen zu den Aufgaben, die entweder schon lange (länger als 30 Sekunden) ausgeführt oder nicht abgeschlossen wurden. Sie müssen diese Informationen für die letzten zwei Tage sammeln:
    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

    Hier können Sie einen Filter setzen, um alle unnötigen Aufgaben zu entfernen. Beispielsweise jene Aufgaben, die sich auf die Replikation beziehen, da deren Ausführung viel mehr Zeit in Anspruch nimmt.

Generieren Sie einen HTML-Bericht, um ihn an die E-Mail-Adresse des Administrators zu senden:

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

Diese gespeicherte Prozedur generiert einen HTML-Bericht über abgeschlossene Aufgaben, die 30 Sekunden lang ausgeführt wurden oder nicht abgeschlossen werden konnten.

Ergebnis

In diesem Artikel habe ich an einem bestimmten Beispiel die Implementierung einer täglichen automatischen Datenerfassung über abgeschlossene Aufgaben im SQL Server Agent untersucht. Diese Informationen helfen dabei, Aufgaben zu ermitteln, die seit langem ausgeführt oder mit einem Fehler abgeschlossen wurden. Es ermöglicht einem Administrator, Maßnahmen zu ergreifen, um solche Fehler in Zukunft zu vermeiden. Beispielsweise ist es möglich, die Ausführung der Aufgabe zu beschleunigen oder die maximale Zeit für die angegebene Aufgabe festzulegen.

Diese Lösung hilft auch bei der Überwachung von Problemen im Zusammenhang mit Sicherungen. Wir werden aber später darauf eingehen, da es nicht ausreicht, sich einmal täglich über wichtige Aufgaben zu benachrichtigen. Es ist notwendig, sofort und regelmäßig eine E-Mail darüber zu senden, bis der Fehler behoben ist.

Wenn Sie Daten von mehreren Servern auswählen müssen, ist es möglich, die Ergebnisse zu kombinieren und sie „über eine E-Mail“ zu versenden.

Referenzen:

» sysjobs
» sysjobserver

Weiterführende Literatur:

Automatische Datenerfassung von Datenbankschemaänderungen in MS SQL Server

Automatische Datenerfassung:Datenbankdateien und logische Laufwerke in MS SQL Server

Datenbank-E-Mail-Benachrichtigungen in MS SQL Server konfigurieren