Wie und wann aktualisiert SQL Agent die Werte für next_run_date / next_run_time?

13

Ich habe in T-SQL an Code gearbeitet, um einem SQL Agent-Job mithilfe des Befehls sp_add_jobschedule in der Datenbank msdb neue Zeitpläne hinzuzufügen. Wenn ich einen neuen Zeitplan (normalerweise eine einmalige Ausführung zu einem bestimmten Datum / einer bestimmten Uhrzeit) hinzufüge und sofort die Werte in sysjobschedules und sysschedules betrachte, kann ich feststellen, dass der neue Zeitplan hinzugefügt wurde und mit der job_id für meinen SQL-Agenten verknüpft ist Job. Die Werte für next_run_date und next_run_time enthalten jedoch 0. Wenn ich zurückkomme und sie mir in zwei oder drei Minuten noch einmal ansehe, zeigen sie immer noch Nullen. Wenn ich jedoch noch 5 oder 10 Minuten später zurückkomme, werden Datum und Uhrzeit des nächsten geplanten Laufs korrekt angezeigt.

Meine Fragen sind also:

  • Wie oft werden diese Werte aktualisiert?
  • Welcher Prozess aktualisiert diese Werte?
  • Wenn ich einen Zeitplan hinzufügen würde, der beispielsweise 1 Minute in der Zukunft liegt, würde dies bedeuten, dass der Job nicht ausgeführt wird, da das Datum / die Uhrzeit für die nächste Ausführung noch nicht aktualisiert wurden?

Beispiel für den Code, mit dem ich einen neuen Zeitplan hinzufüge:

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

Dabei ist @jobID eine Binärdatei (16), die die job_id des betreffenden Jobs enthält. @ScheduleRunDate und @ScheduleRunTime sind INTs mit Datum und Uhrzeit.

BBlake
quelle
3
Es wird über einen SQL Agent-Job aktualisiert. Welches wird über einen SQL Agent-Auftrag aktualisiert. Rekursionisten vereinen sich!
Aaron Bertrand
1
Entschuldigung. Ich hatte seit einer Weile keine Chance mehr, zurück zu kreisen.
BBlake

Antworten:

16

Kurze Antwort

Es sieht so aus, als würden die Daten in alle 20 Minuten msdb.dbo.sysjobschedulesvon einem Hintergrundthread in SQL Agent aktualisiert SQLAgent - Schedule Saver(oder seltener, wenn xp_sqlagent_notifysie nicht aufgerufen wurden und in der Zwischenzeit keine Jobs ausgeführt wurden).

Weitere Informationen finden Sie next_scheduled_run_datein msdb.dbo.sysjobactivity. Dies wird in Echtzeit jedes Mal aktualisiert, wenn ein Job geändert oder ausgeführt wird. Als zusätzlichen Bonus sysjobactivityspeichert das die Daten richtig (als Datum / Uhrzeit-Spalte), wodurch es viel einfacher ist, damit zu arbeiten als mit diesen dummen INTs.

Das ist die kurze Antwort:

Es kann bis zu 20 Minuten dauern, bis Sysjobpläne die Wahrheit widerspiegeln. Die Systemaktivität ist jedoch immer auf dem neuesten Stand. Wenn Sie mehr darüber wissen wollen, oder wie ich es herausgefunden habe ...


Lange Antwort

Wenn Sie dem Kaninchen einen Moment lang folgen möchten, wenn Sie anrufen sp_add_jobschedule, wird diese Ereigniskette in Gang gesetzt:

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

Jetzt können wir das Kaninchen nicht mehr weiter verfolgen, weil wir nicht wirklich sehen können, was es xp_sqlagent_notifytut. Ich denke jedoch, dass wir davon ausgehen können, dass dieses erweiterte Verfahren mit dem Agentenservice interagiert und dass es eine Änderung an diesem bestimmten Job und Zeitplan gegeben hat. Indem wir einen serverseitigen Trace ausführen, können wir sofort feststellen, dass der folgende dynamische SQL-Code vom SQL-Agenten aufgerufen wird:

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'

Es scheint, dass sysjobactivitydas sofort aktualisiert wird und sysjobschedulesnur nach einem Zeitplan aktualisiert wird. Wenn wir den neuen Zeitplan auf einmal am Tag ändern, z

@freq_type=4, 
@freq_interval=1, 
@freq_subday_type=1, 
@freq_subday_interval=0, 
@freq_relative_interval=0, 
@freq_recurrence_factor=1, 

Wir sehen immer noch das sofortige Update auf sysjobactivitywie oben und dann ein weiteres Update, nachdem der Job beendet ist. Verschiedene Updates stammen aus dem Hintergrund und anderen Threads in SQL Agent, z.

SQLAgent - Job Manager
SQLAgent - Update job activity
SQLAgent - Job invocation engine
SQLAgent - Schedule Saver

Ein Hintergrund-Thread (der "Schedule Saver" -Thread) erscheint und wird aktualisiert sysjobschedules. meiner ersten Untersuchung zufolge ist dies alle 20 Minuten der Fall und geschieht nur, wenn xp_sqlagent_notifyein Aufruf aufgrund einer Änderung eines Jobs seit seiner letzten Ausführung erfolgt ist (ich habe keine weiteren Tests durchgeführt, um festzustellen, was passiert, wenn ein Job ausgeführt wurde) geändert und ein anderer wurde ausgeführt, wenn der Thread "Schedule Saver" beide aktualisiert - ich vermute, es muss, überlässt dies aber dem Leser als Übung).

Ich bin nicht sicher, ob der 20-Minuten-Zyklus vom Zeitpunkt des Starts von SQL Agent, von Mitternacht oder von einem bestimmten Computer abweicht. Auf zwei verschiedenen Instanzen auf demselben physischen Server wurde der Thread "Schedule Saver" sysjobschedulesauf beiden Instanzen fast zur gleichen Zeit aktualisiert - 18:31:37 und 18:51:37 auf einer und 18:31:39. 18:51:39 auf der anderen Seite. Ich habe den SQL Server-Agenten auf diesen Servern nicht gleichzeitig gestartet, aber es besteht die Möglichkeit, dass die Startzeiten 20 Minuten versetzt sind. Ich bezweifle es, aber ich habe momentan keine Zeit, es zu bestätigen, indem ich Agent auf einem von ihnen neu starte und auf weitere Updates warte.

Ich weiß, wer es getan hat und wann es passiert ist, weil ich dort einen Abzug platziert und ihn erfasst habe, falls ich ihn nicht in der Spur finden konnte oder ich ihn versehentlich herausgefiltert habe.

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

Das heißt, es ist nicht schwer, mit einem Standard-Trace zu fangen, dieser kommt sogar als nicht-dynamisches DML durch:

UPDATE msdb.dbo.sysjobschedules 
  SET next_run_date = 20120817, 
      next_run_time = 20000 
 WHERE (job_id = 0xB87B329BFBF7BA40B30D9B27E0B120DE 
 and schedule_id = 8)

Wenn Sie eine stärker gefilterte Ablaufverfolgung ausführen möchten, um dieses Verhalten über einen längeren Zeitraum nachzuverfolgen (z. B. bei einem Neustart des SQL-Agenten statt bei Bedarf), können Sie eine Ablaufverfolgung ausführen, die appname = 'SQLAgent - Schedule Saver'... hat.

Also ich denke, wenn du die nächste Laufzeit sofort wissen willst, sieh dir das an sysjobactivity, nicht sysjobschedules. Diese Tabelle wird direkt vom Agenten oder seinen Hintergrundthreads ("Jobaktivität aktualisieren", "Jobmanager" und "Jobaufruf-Engine") aktualisiert, wenn eine Aktivität stattfindet oder von dieser benachrichtigt wird xp_sqlagent_notify.

Beachten Sie jedoch, dass es sehr einfach ist, eine der beiden Tabellen auszutricksen, da es keinen Schutz gegen das Löschen von Daten aus diesen Tabellen gibt. (Wenn Sie sich beispielsweise für eine Bereinigung entschieden haben, können Sie problemlos alle Zeilen für diesen Job aus der Aktivitätstabelle entfernen.) In diesem Fall bin ich mir nicht sicher, wie der SQL Server-Agent das nächste Ausführungsdatum abruft oder speichert. Vielleicht verdient eine spätere Untersuchung mehr, wenn ich etwas Freizeit habe ...

Aaron Bertrand
quelle
Wenn ein Job noch nicht zum ersten Mal ausgeführt wurde, zeigen sysjobschedules (eventuell) die korrekten Werte für next_run_date und next_run_time an, während sysjobactivity.next_scheduled_run_date bis nach der ersten Ausführung null bleibt. Wenn Sie den Wert von sysjobactivity abrufen, müssen Sie dies in einer Unterabfrage tun, die sich nach job_id gruppiert und das MAX (next_scheduled_run_date) abruft.
Mark Freeman
0

msdb.dbo.sp_help_jobscheint immer das richtige aktuelle next_run_date/ zurückzugeben next_run_time.

Es wird verwendet sp_get_composite_job_info, um den folgenden Aufruf tatsächlich abzurufen 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

Da sysjobschedulescheint unzuverlässig zu sein, würde ich nur verwenden sp_help_job.

lockenhaarigenius
quelle