短い答え
のデータmsdb.dbo.sysjobschedules
は、SQLエージェントのバックグラウンドスレッドによって更新され、SQLAgent - Schedule Saver
20分ごとに(またはxp_sqlagent_notify
呼び出されておらず、その間にジョブが実行されていない場合は頻度が低くなります)識別されます。
より正確な情報については、見てnext_scheduled_run_date
の中でmsdb.dbo.sysjobactivity
。これは、ジョブが変更されるかジョブが実行されるたびにリアルタイムで更新されます。追加のボーナスとして、sysjobactivity
データは正しい方法で(日付時刻列として)保存されるため、これらの愚かなINTよりも作業がはるかに簡単になります。
それは簡単な答えです:
sysjobschedulesが真実を反映するまでに最大20分かかる場合があります。ただし、sysjobactivityは常に最新です。これについてさらに詳細を知りたい場合、または私がそれをどのように理解したか...
ロングアンサー
ウサギをしばらく追跡したい場合、を呼び出すとsp_add_jobschedule
、この一連のイベントが動き始めます。
msdb.dbo.sp_add_jobschedule == calls ==> msdb.dbo.sp_add_schedule
msdb.dbo.sp_attach_schedule
msdb.dbo.sp_attach_schedule == calls ==> msdb.dbo.sp_sqlagent_notify
msdb.dbo.sp_sqlagent_notify == calls ==> msdb.dbo.xp_sqlagent_notify
さて、これ以上うさぎを追いかけることはできませんxp_sqlagent_notify
。何をするのかを実際に覗くことができないからです。しかし、この拡張手順はエージェントサービスとやり取りし、この特定のジョブとスケジュールに変更があったことを伝えていると推測できます。サーバー側のトレースを実行すると、すぐに次の動的SQLがSQLエージェントによって呼び出されることがわかります。
exec sp_executesql N'DECLARE @nextScheduledRunDate DATETIME
SET @nextScheduledRunDate = msdb.dbo.agent_datetime(@P1, @P2)
UPDATE msdb.dbo.sysjobactivity
SET next_scheduled_run_date = @nextScheduledRunDate
WHERE session_id = @P3 AND job_id = @P4',
N'@P1 int,@P2 int,@P3 int,@P4 uniqueidentifier',
20120819,181600,5,'36924B24-9706-4FD7-8B3A-1F9F0BECB52C'
と思われsysjobactivity
、すぐに更新され、sysjobschedules
唯一のスケジュールで更新されます。新しいスケジュールを1日1回に変更した場合、たとえば
@freq_type=4,
@freq_interval=1,
@freq_subday_type=1,
@freq_subday_interval=0,
@freq_relative_interval=0,
@freq_recurrence_factor=1,
sysjobactivity
上記のようにすぐに更新が行われ、ジョブの終了後に別の更新が行われます。さまざまな更新は、SQLエージェント内のバックグラウンドおよびその他のスレッドから行われます。例:
SQLAgent - Job Manager
SQLAgent - Update job activity
SQLAgent - Job invocation engine
SQLAgent - Schedule Saver
バックグラウンドスレッド(「スケジュールセーバー」スレッド)が最終的に登場し、更新されますsysjobschedules
。私の最初の調査から、これは20分ごとでありxp_sqlagent_notify
、最後に実行されてからジョブに加えられた変更のために呼び出された場合にのみ発生します「スケジュールセーバー」スレッドが両方を更新する場合、変更され、別のスレッドが実行されます-必要と思われますが、読者への演習として残します)。
20分サイクルが、SQLエージェントの起動時から、または深夜から、またはマシン固有の何かからオフセットされているかどうかはわかりません。同じ物理サーバー上の2つの異なるインスタンスで、「スケジュールセーバー」スレッドが更新されsysjobschedules
、両方のインスタンスでほぼ同時に-1つは18:31:37&18:51:37、1つは18:31:39&他方の18:51:39。これらのサーバーでSQL Serverエージェントを同時に起動しませんでしたが、開始時間が20分のオフセットになる可能性がわずかにあります。疑いがありますが、現時点でエージェントのいずれかでエージェントを再起動し、さらに更新が行われるのを待つ時間はありません。
誰がそれをしたのか、それがいつ起こったのかを知っています。これは、トレース内でトリガーを見つけられなかった場合、または不注意でフィルターした場合に備えて、トリガーを配置してキャプチャしたためです。
CREATE TABLE dbo.JobAudit
(
[action] CHAR(1),
[table] CHAR(1),
hostname SYSNAME NOT NULL DEFAULT HOST_NAME(),
appname SYSNAME NOT NULL DEFAULT PROGRAM_NAME(),
dt DATETIME2 NOT NULL DEFAULT SYSDATETIME()
);
CREATE TRIGGER dbo.schedule1 ON dbo.sysjobactivity FOR INSERT
AS
INSERT dbo.JobAudit([action], [table] SELECT 'I', 'A';
GO
CREATE TRIGGER dbo.schedule2 ON dbo.sysjobactivity FOR UPDATE
AS
INSERT dbo.JobAudit([action], [table] SELECT 'U', 'A';
GO
CREATE TRIGGER dbo.schedule3 ON dbo.sysjobschedules FOR INSERT
AS
INSERT dbo.JobAudit([action], [table] SELECT 'I', 'S';
GO
CREATE TRIGGER dbo.schedule4 ON dbo.sysjobschedules FOR UPDATE
AS
INSERT dbo.JobAudit([action], [table] SELECT 'U', 'S';
GO
とは言っても、標準のトレースでキャッチするのは難しくありません。これは、動的でないDMLとしても実現します。
UPDATE msdb.dbo.sysjobschedules
SET next_run_date = 20120817,
next_run_time = 20000
WHERE (job_id = 0xB87B329BFBF7BA40B30D9B27E0B120DE
and schedule_id = 8)
フィルター処理されたトレースを実行して、この動作を経時的に追跡する場合(たとえば、オンデマンドではなくSQLエージェントの再起動を通じて持続する場合)、appname = 'SQLAgent - Schedule Saver'
... を持つトレースを実行できます。
したがって、次の実行時間をすぐに知りたい場合はsysjobactivity
、ではなく、を見てくださいsysjobschedules
。このテーブルは、アクティビティが発生したとき、または通知されたときに、エージェントまたはそのバックグラウンドスレッド(「ジョブアクティビティの更新」、「ジョブマネージャ」、「ジョブ呼び出しエンジン」)によって直接更新されxp_sqlagent_notify
ます。
ただし、これらのテーブルからデータを削除することに対する保護がないため、どちらかのテーブルを非常に簡単に作成することに注意してください。(たとえば、クリーンアップすることにした場合、アクティビティテーブルからそのジョブのすべての行を簡単に削除できます。)この場合、SQL Serverエージェントが次の実行日を取得または保存する方法が正確にわかりません。後日、自由時間があるときにもっと調査する価値があるかもしれません...