はじめに
データベース管理者は、どのタスクとそれらがどのように完了したかを知ることが重要です。このプロセスを簡素化するには、手動で実行するのではなく、自動化することをお勧めします。
この記事では、SQLServerエージェントの完了したタスクに関するデータを自動的に収集する方法を特定の例で分析します。
ソリューション
アルゴリズム:
- タスクを選択するインスタンスを作成します。
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これを行うには、sysjobserversおよびsysjobs_viewインスタンスを使用します。
- 選択したデータを格納するテーブルを作成します。
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 - SQL Serverエージェントでタスクを作成し、長時間(30秒以上)実行されたタスクまたは完了できなかったタスクに関する情報を取得します。過去2日間、この情報を収集する必要があります。
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ここで、フィルターを設定して不要なタスクをすべて削除できます。たとえば、完了するまでにはるかに時間がかかるため、レプリケーションを参照するタスク。
HTMLレポートを生成して、管理者の電子メールに送信します:
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 @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+'TASK';
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+'STATUS';
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+'DATE AND TIME';
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+'DURATION';
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+'MESSAGE';
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+'SERVER';
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
@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 @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(@Job_GUID as nvarchar(255));
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+coalesce(@Job_Name,'');
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+coalesce(@LastFinishRunState,'');
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+rep.GetDateFormat(@LastDateTime, default)+' '+rep.GetTimeFormat(@LastDateTime, default);--cast(@InsertDate as nvarchar(max));
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+coalesce(@LastRunDurationString,'');
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+coalesce(@LastOutcomeMessage, '');
set @example@sqldat.com+'</TD>';
set @example@sqldat.com+'<TD>';
set @example@sqldat.com+coalesce(@Server, '');
set @example@sqldat.com+'</TD>';
delete from @tbl
where example@sqldat.com;
set @example@sqldat.com+'</TR>';
end
set @example@sqldat.com+'</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 @example@sqldat.com+'<br><br>For the detailed information, please refer to the table DATABASE_NAME.srv.ShortInfoRunJobs';
END
GOを参照してください。 このストアドプロシージャは、30秒間実行されたタスク、または完了できなかったタスクに関するHTMLレポートを生成します。
結果
この記事では、特定の例で、SQLServerエージェントで完了したタスクに関する毎日の自動データ収集の実装について説明しました。この情報は、長期間実行されたタスク、またはエラーで完了したタスクを判別するのに役立ちます。これにより、管理者は将来このような間違いを回避するための対策を講じることができます。たとえば、タスクの実行速度を上げたり、指定したタスクの最大時間を設定したりできます。
このソリューションは、バックアップに関連する問題の監視にも役立ちます。それでも、重要なタスクについて1日1回通知するだけでは不十分なため、後で説明します。エラーが修正されるまで、すぐに定期的にメールで送信する必要があります。
複数のサーバーからデータを選択する必要がある場合は、結果を組み合わせて「1通のメールで」送信することができます。
参照:
»sysjobs
»sysjobservers
参考資料:
MSSQLServerでのデータベーススキーマ変更の自動データ収集
自動データ収集:MSSQLServerのデータベースファイルと論理ドライブ
MSSQLServerでのデータベースメール通知の構成