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.
Respuestas:
Respuesta corta
Parece que los datos
msdb.dbo.sysjobschedules
se actualizan mediante un subproceso en segundo plano en el Agente SQL, identificado comoSQLAgent - Schedule Saver
, cada 20 minutos (o con menos frecuencia, sixp_sqlagent_notify
no se ha llamado y mientras tanto no se han ejecutado trabajos).Para obtener información más precisa, mira
next_scheduled_run_date
enmsdb.dbo.sysjobactivity
. Esto se actualiza en tiempo real cada vez que se cambia un trabajo o se ejecuta un trabajo. Como una ventaja adicional,sysjobactivity
almacena 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:
Respuesta larga
Si te interesa seguir al conejo por un momento, cuando llamas
sp_add_jobschedule
, esta cadena de eventos se pone en marcha:Ahora, no podemos perseguir al conejo más, porque realmente no podemos echar un vistazo a lo que
xp_sqlagent_notify
hace. 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:Parece que
sysjobactivity
se actualiza de inmediato ysysjobschedules
solo se actualiza en un horario. Si cambiamos el nuevo horario para que sea una vez al día, por ej.Todavía vemos la actualización inmediata a la
sysjobactivity
anterior, 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: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 sixp_sqlagent_notify
se 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.
Dicho esto, no es difícil atrapar con un rastreo estándar, este incluso se presenta como DML no dinámico:
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
, nosysjobschedules
. 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 notificaxp_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 ...
fuente
msdb.dbo.sp_help_job
siempre parece devolver el correctonext_run_date
/ realnext_run_time
.Utiliza
sp_get_composite_job_info
, que hace la siguiente llamada para recuperar realmente elnext_run_date/time
.Como
sysjobschedule
parece no ser confiable, simplemente lo usaríasp_help_job
.fuente