¿Cómo y cuándo el Agente SQL actualiza los valores next_run_date / next_run_time?


13

He estado trabajando en código en T-SQL para agregar nuevas programaciones a un trabajo del Agente SQL utilizando el proceso sp_add_jobschedule en la base de datos msdb. Cuando agrego una nueva programación (generalmente una ejecución única en una fecha / hora específica) e inmediatamente miro los valores en sysjobschedules y sysschedules, puedo ver que la nueva programación se ha agregado y está vinculada al job_id para mi Agente SQL trabajo. Sin embargo, los valores para next_run_date y next_run_time tienen 0 en ellos. Cuando regreso y los miro nuevamente en 2 o 3 minutos, todavía muestran 0 en ellos. Sin embargo, cuando vuelvo otros 5 o 10 minutos más tarde, ahora muestra correctamente los valores de fecha y hora correspondientes a la próxima ejecución programada.

Entonces mis preguntas son:

  • ¿Con qué frecuencia se actualizan estos valores?
  • ¿Qué proceso es el que actualiza estos valores?
  • Si tuviera que agregar un horario que fuera, digamos, 1 minuto en el futuro, ¿eso significa que el trabajo no se ejecutará ya que la siguiente fecha / hora de ejecución no se ha actualizado todavía?

Ejemplo del código que uso para agregar un nuevo horario:

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

donde @jobID es binario (16) que contiene el job_id del trabajo en cuestión, @ScheduleRunDate y @ScheduleRunTime son INT con la fecha y la hora respectivamente.


3
Se actualiza a través de un trabajo del Agente SQL. Que se actualiza a través de un trabajo del Agente SQL. ¡Los recursivos se unen!
Aaron Bertrand

1
Disculpas No he tenido la oportunidad de regresar en un tiempo.
BBlake

Respuestas:


16

Respuesta corta

Parece que los datos msdb.dbo.sysjobschedulesse actualizan mediante un subproceso en segundo plano en el Agente SQL, identificado como SQLAgent - Schedule Saver, cada 20 minutos (o con menos frecuencia, si xp_sqlagent_notifyno se ha llamado y mientras tanto no se han ejecutado trabajos).

Para obtener información más precisa, mira next_scheduled_run_dateen msdb.dbo.sysjobactivity. Esto se actualiza en tiempo real cada vez que se cambia un trabajo o se ejecuta un trabajo. Como una ventaja adicional, sysjobactivityalmacena los datos de la manera correcta (como una columna de fecha y hora), lo que hace que sea mucho más fácil trabajar con esos estúpidos INT.

Esa es la respuesta corta:

Pueden pasar hasta 20 minutos antes de que sysjobschedules refleje la verdad; sin embargo, la sysjobactivity siempre estará actualizada. Si quieres muchos más detalles sobre esto, o cómo lo descubrí ...


Respuesta larga

Si te interesa seguir al conejo por un momento, cuando llamas sp_add_jobschedule, esta cadena de eventos se pone en marcha:

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

Ahora, no podemos perseguir al conejo más, porque realmente no podemos echar un vistazo a lo que xp_sqlagent_notifyhace. Pero creo que podemos suponer que este procedimiento extendido interactúa con el servicio del Agente y le dice que ha habido un cambio en este trabajo y horario específicos. Al ejecutar un rastreo del lado del servidor, podemos ver que, de inmediato, el Agente SQL llama al siguiente SQL dinámico:

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'

Parece que sysjobactivityse actualiza de inmediato y sysjobschedulessolo se actualiza en un horario. Si cambiamos el nuevo horario para que sea una vez al día, por ej.

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

Todavía vemos la actualización inmediata a la sysjobactivityanterior, y luego otra actualización una vez que finaliza el trabajo. Varias actualizaciones provienen de fondo y otros hilos dentro del Agente SQL, por ejemplo:

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

Un subproceso de fondo (el subproceso "Ahorro de horario") aparece y se actualiza sysjobschedules; de mi investigación inicial parece que esto es cada 20 minutos, y solo sucede si xp_sqlagent_notifyse ha llamado debido a un cambio realizado en un trabajo desde la última vez que se ejecutó (no realicé ninguna prueba adicional para ver qué sucede si se ha realizado un trabajo cambiado y se ha ejecutado otro, si el hilo "Schedule Saver" actualiza ambos, sospecho que debe hacerlo, pero lo dejaré como un ejercicio para el lector).

No estoy seguro de si el ciclo de 20 minutos está compensado desde el inicio del Agente SQL, o desde la medianoche, o desde algo específico de la máquina. En dos instancias diferentes en el mismo servidor físico, el hilo "Schedule Saver" se actualizó sysjobschedules, en ambas instancias, casi al mismo tiempo: 18:31:37 y 18:51:37 en una, y 18:31:39 y 18:51:39 por el otro. No inicié el Agente SQL Server al mismo tiempo en estos servidores, pero existe la posibilidad remota de que las horas de inicio sean 20 minutos de compensación. Lo dudo, pero no tengo tiempo en este momento para confirmar reiniciando el Agente en uno de ellos y esperando que ocurran más actualizaciones.

Sé quién lo hizo, y cuándo sucedió, porque puse un gatillo allí y lo capturé, en caso de que no pudiera encontrarlo en el rastro, o lo filté inadvertidamente.

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

Dicho esto, no es difícil atrapar con un rastreo estándar, este incluso se presenta como DML no dinámico:

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

Si desea ejecutar una traza más filtrada para rastrear este comportamiento a lo largo del tiempo (por ejemplo, persistir a través del reinicio del Agente SQL en lugar de bajo demanda), puede ejecutar uno que tenga appname = 'SQLAgent - Schedule Saver'...

Así que creo que si quieres saber el próximo tiempo de ejecución inmediatamente, mira sysjobactivity, no sysjobschedules. Esta tabla es actualizada directamente por el Agente o sus subprocesos en segundo plano ("Actualizar actividad de trabajo", "Administrador de trabajos" y "Motor de invocación de trabajos") a medida que ocurre la actividad o según lo notifica xp_sqlagent_notify.

Sin embargo, tenga en cuenta que es muy fácil eliminar cualquier tabla, ya que no hay protecciones contra la eliminación de datos de estas tablas. (Entonces, si decidió limpiar, por ejemplo, puede eliminar fácilmente todas las filas para ese trabajo de la tabla de actividades). En este caso, no estoy exactamente seguro de cómo el Agente SQL Server obtiene o guarda la próxima fecha de ejecución. Quizás merezca más investigación en una fecha posterior cuando tenga algo de tiempo libre ...


Si un trabajo aún no se ha ejecutado por primera vez, los sysjobschedules (eventualmente) mostrarán los valores correctos para next_run_date y next_run_time, mientras que sysjobactivity.next_scheduled_run_date permanece nulo hasta después de la primera ejecución. Al obtener el valor de sysjobactivity, debe hacerlo en una subconsulta que se agrupa por job_id y obtiene el MAX (next_scheduled_run_date).
Mark Freeman

0

msdb.dbo.sp_help_jobsiempre parece devolver el correcto next_run_date/ real next_run_time.

Utiliza sp_get_composite_job_info, que hace la siguiente llamada para recuperar realmente el 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

Como sysjobscheduleparece no ser confiable, simplemente lo usaría sp_help_job.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.