Introducción
Es importante que un administrador de base de datos sepa qué tareas y cómo se han completado. Para simplificar este proceso, es mejor automatizarlo, en lugar de hacerlo manualmente.
En este artículo, analizaré en un ejemplo particular cómo recopilar automáticamente datos sobre las tareas completadas del Agente SQL Server.
Solución
Algoritmo:
- Cree una instancia para seleccionar tareas:
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
Para ello, utilice las instancias sysjobservers y sysjobs_view.
- Cree una tabla para almacenar los datos seleccionados:
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
- Cree una tarea en el Agente SQL Server y obtenga información sobre aquellas tareas que se han ejecutado durante mucho tiempo (más de 30 segundos) o que no se completaron. Debe recopilar esta información durante los últimos dos días:
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
Aquí puede configurar un filtro para eliminar todas las tareas innecesarias. Por ejemplo, aquellas tareas que hacen referencia a la replicación ya que lleva mucho más tiempo completarlas.
Genere un informe HTML para enviarlo al correo electrónico de los administradores:
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
Este procedimiento almacenado genera un informe HTML sobre las tareas completadas que se han ejecutado durante 30 segundos o que no se pudieron completar.
Resultado
En este artículo, he explorado en un ejemplo particular la implementación de una recopilación automática diaria de datos sobre las tareas completadas en el Agente SQL Server. Esta información ayuda a determinar las tareas que se han ejecutado durante mucho tiempo o se completaron con un error. Permite que un administrador tome medidas para evitar tales errores en el futuro. Por ejemplo, es posible hacer que la tarea se ejecute más rápido o establecer el tiempo máximo para la tarea especificada.
Esta solución también ayuda a controlar los problemas relacionados con las copias de seguridad. Aún así, lo discutiremos más adelante, ya que no es suficiente notificar sobre tareas importantes una vez al día. Es necesario enviar correos electrónicos sobre ellos de inmediato y con regularidad hasta que se solucione el error.
Si necesita seleccionar datos de varios servidores, entonces es posible combinar los resultados y enviarlos `a través de un correo electrónico.
Referencias:
» trabajos del sistema
» servidores de trabajos del sistema
Lecturas adicionales:
Recopilación automática de datos de cambios en el esquema de la base de datos en MS SQL Server
Recopilación automática de datos:archivos de base de datos y unidades lógicas en MS SQL Server
Configuración de notificaciones de correo electrónico de base de datos en MS SQL Server