Risposta breve
Sembra che i dati in msdb.dbo.sysjobschedules
siano aggiornati da un thread in background in SQL Agent, identificato come SQLAgent - Schedule Saver
ogni 20 minuti (o meno frequentemente, se xp_sqlagent_notify
non è stato chiamato e nel frattempo non sono stati eseguiti lavori).
Per informazioni più precise, sguardo next_scheduled_run_date
in msdb.dbo.sysjobactivity
. Questo viene aggiornato in tempo reale ogni volta che un lavoro viene modificato o è stato eseguito un lavoro. Come bonus aggiuntivo, sysjobactivity
memorizza i dati nel modo giusto (come una colonna datetime), rendendo molto più facile lavorare con quegli stupidi INT.
Questa è la risposta breve:
Potrebbero essere necessari fino a 20 minuti prima che sysjobschedules rifletta la verità; tuttavia, la sysjobactivity sarà sempre aggiornata. Se vuoi molti più dettagli su questo, o su come l'ho capito ...
Risposta lunga
Se ti interessa seguire il coniglio per un momento, quando chiami sp_add_jobschedule
, questa catena di eventi viene messa in moto:
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
Ora, non possiamo più inseguire il coniglio, perché non possiamo davvero dare un'occhiata a ciò che xp_sqlagent_notify
fa. Ma penso che possiamo presumere che questa procedura estesa interagisca con il servizio Agente e gli dica che c'è stata una modifica a questo specifico lavoro e programma. Eseguendo una traccia sul lato server possiamo vedere che, immediatamente, il seguente SQL dinamico viene chiamato dall'agente 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'
Sembra che sysjobactivity
sia aggiornato immediatamente e sysjobschedules
sia aggiornato solo su una pianificazione. Se cambiamo il nuovo programma per essere una volta al giorno, ad es
@freq_type=4,
@freq_interval=1,
@freq_subday_type=1,
@freq_subday_interval=0,
@freq_relative_interval=0,
@freq_recurrence_factor=1,
Vediamo ancora l'aggiornamento immediato sysjobactivity
come sopra e quindi un altro aggiornamento al termine del lavoro. Vari aggiornamenti provengono da background e altri thread all'interno di SQL Agent, ad esempio:
SQLAgent - Job Manager
SQLAgent - Update job activity
SQLAgent - Job invocation engine
SQLAgent - Schedule Saver
Un thread in background (il thread "Schedule Saver") alla fine arriva e si aggiorna sysjobschedules
; dalla mia indagine iniziale sembra che questo avvenga ogni 20 minuti e si verifica solo se xp_sqlagent_notify
è stato chiamato a causa di una modifica apportata a un lavoro dall'ultima volta che è stato eseguito (non ho eseguito ulteriori test per vedere cosa succede se un lavoro è stato è stato modificato e ne è stato eseguito un altro, se il thread "Schedule Saver" si aggiorna entrambi - sospetto che debba, ma lo lascerò come esercizio al lettore).
Non sono sicuro che il ciclo di 20 minuti sia sfalsato rispetto all'avvio di SQL Agent, o da mezzanotte o da qualcosa di specifico della macchina. In due istanze diverse sullo stesso server fisico, il thread "Schedule Saver" si è aggiornato sysjobschedules
, in entrambe le istanze, quasi nello stesso momento - 18:31:37 e 18:51:37 su uno e 18:31:39 & 18:51:39 dall'altro. Non ho avviato SQL Server Agent contemporaneamente su questi server, ma esiste una remota possibilità che gli orari di avvio abbiano un offset di 20 minuti. Ne dubito, ma in questo momento non ho tempo per confermare riavviando Agent su uno di essi e aspettando che avvengano altri aggiornamenti.
So chi l'ha fatto e quando è successo, perché ho inserito un grilletto e l'ho catturato, nel caso in cui non riuscissi a trovarlo nella traccia o l'ho inavvertitamente filtrato.
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
Detto questo, non è difficile da individuare con una traccia standard, questa viene persino come DML non dinamico:
UPDATE msdb.dbo.sysjobschedules
SET next_run_date = 20120817,
next_run_time = 20000
WHERE (job_id = 0xB87B329BFBF7BA40B30D9B27E0B120DE
and schedule_id = 8)
Se si desidera eseguire una traccia più filtrata per tenere traccia di questo comportamento nel tempo (ad esempio, il persistere tramite riavvii dell'agente SQL anziché su richiesta), è possibile eseguirne uno con appname = 'SQLAgent - Schedule Saver'
...
Quindi penso che se vuoi sapere immediatamente il prossimo tempo di esecuzione, guarda sysjobactivity
no sysjobschedules
. Questa tabella viene aggiornata direttamente dall'agente o dai relativi thread in background ("Aggiorna attività lavoro", "Gestione lavoro" e "Motore di chiamata lavoro") quando l'attività si verifica o quando viene notificata da xp_sqlagent_notify
.
Tenere presente, tuttavia, che è molto semplice eseguire l'archiviazione di entrambe le tabelle, poiché non esistono protezioni contro l'eliminazione dei dati da queste tabelle. (Quindi, se hai deciso di ripulire, ad esempio, puoi facilmente rimuovere tutte le righe per quel lavoro dalla tabella delle attività.) In questo caso non sono esattamente sicuro di come SQL Server Agent ottenga o salvi la prossima data di esecuzione. Forse degno di ulteriori indagini in un secondo momento, quando avrò del tempo libero ...