Come e quando SQL Agent aggiorna i valori next_run_date / next_run_time?


13

Ho lavorato sul codice in T-SQL per aggiungere nuove pianificazioni a un processo di SQL Agent usando il proc sp_add_jobschedule nel database msdb. Quando aggiungo una nuova pianificazione (in genere un run-once in una data / ora specifica) e guardo immediatamente i valori in sysjobschedules e sysschedules, posso vedere che la nuova pianificazione è stata aggiunta ed è legata al job_id per il mio agente SQL lavoro. Tuttavia, i valori per next_run_date e next_run_time hanno 0 in essi. Quando torno a guardarli di nuovo in 2 o 3 minuti, mostrano ancora 0 in essi. Tuttavia, quando torno altri 5 o 10 minuti dopo, ora mostra correttamente i valori di data e ora corrispondenti alla successiva esecuzione pianificata.

Quindi le mie domande sono:

  • Con quale frequenza vengono aggiornati questi valori?
  • Quale processo aggiorna questi valori?
  • Se dovessi aggiungere una pianificazione, diciamo, 1 minuto in futuro, ciò significa che il lavoro non verrà eseguito dal prossimo giorno_data_ora / ora non sono ancora stati aggiornati?

Esempio del codice che utilizzo per aggiungere una nuova pianificazione:

exec msdb.dbo.sp_add_jobschedule @job_id = @jobID
                    , @name = @JobName
                    , @enabled = 1
                    , @freq_type = 1
                    , @freq_interval = 0
                    , @freq_subday_type = 0
                    , @freq_subday_interval = 0
                    , @freq_relative_interval = 0
                    , @freq_recurrence_factor = 0
                    , @active_start_date = @ScheduleRunDate
                    , @active_end_date = 99991231
                    , @active_start_time = @ScheduleRunTime
                    , @active_end_time = 235959

dove @jobID è binario (16) che contiene il job_id del lavoro in questione, @ScheduleRunDate e @ScheduleRunTime sono INT rispettivamente con la data e l'ora.


3
Viene aggiornato tramite un processo di SQL Agent. Che viene aggiornato tramite un processo di SQL Agent. I ricorsionisti si uniscono!
Aaron Bertrand

1
Scuse. Non ho avuto la possibilità di tornare indietro da un po '.
BBlake,

Risposte:


16

Risposta breve

Sembra che i dati in msdb.dbo.sysjobschedulessiano aggiornati da un thread in background in SQL Agent, identificato come SQLAgent - Schedule Saverogni 20 minuti (o meno frequentemente, se xp_sqlagent_notifynon è stato chiamato e nel frattempo non sono stati eseguiti lavori).

Per informazioni più precise, sguardo next_scheduled_run_datein msdb.dbo.sysjobactivity. Questo viene aggiornato in tempo reale ogni volta che un lavoro viene modificato o è stato eseguito un lavoro. Come bonus aggiuntivo, sysjobactivitymemorizza 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_notifyfa. 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 sysjobactivitysia aggiornato immediatamente e sysjobschedulessia 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 sysjobactivitycome 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 sysjobactivityno 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 ...


Se un lavoro non è stato ancora eseguito per la prima volta, sysjobschedules mostrerà (eventualmente) i valori corretti per next_run_date e next_run_time, mentre sysjobactivity.next_scheduled_run_date rimane null fino a dopo la prima esecuzione. Quando si ottiene il valore da sysjobactivity, è necessario farlo in una sottoquery che raggruppa per job_id e ottiene il MAX (next_scheduled_run_date).
Mark Freeman,

0

msdb.dbo.sp_help_jobsembra sempre restituire il corretto next_run_date/ next_run_time.

Usa sp_get_composite_job_info, che fa la seguente chiamata per recuperare effettivamente il file next_run_date/time.

      IF ((@@microsoftversion / 0x01000000) >= 8) -- SQL Server 8.0 or greater
        INSERT INTO @xp_results
        EXECUTE master.dbo.xp_sqlagent_enum_jobs @can_see_all_running_jobs, @job_owner, @job_id
      ELSE
        INSERT INTO @xp_results
        EXECUTE master.dbo.xp_sqlagent_enum_jobs @can_see_all_running_jobs, @job_owner

Dal momento che sysjobschedulesembra essere inaffidabile, vorrei solo usare sp_help_job.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.