Resposta curta
Parece que os dados msdb.dbo.sysjobschedules
são atualizados por um encadeamento em segundo plano no SQL Agent, identificado comoSQLAgent - Schedule Saver
cada 20 minutos (ou menos frequentemente, se xp_sqlagent_notify
não tiver sido chamado e nenhum trabalho tiver sido executado nesse meio tempo).
Para obter informações mais precisas, olhada next_scheduled_run_date
no msdb.dbo.sysjobactivity
. Isso é atualizado em tempo real sempre que um trabalho é alterado ou um trabalho é executado. Como um bônus adicional, osysjobactivity
armazena os dados da maneira certa (como uma coluna de data e hora), facilitando muito o trabalho com essas INTs estúpidas.
Essa é a resposta curta:
Pode levar até 20 minutos para que os sysjobschedules reflitam a verdade; no entanto, a atividade do sistema sempre estará atualizada. Se você quiser muito mais detalhes sobre isso, ou como eu descobri ...
Resposta longa
Se você quiser seguir o coelho por um momento, quando ligar sp_add_jobschedule
, essa cadeia de eventos será acionada:
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
Agora, não podemos mais perseguir o coelho, porque realmente não podemos espiar o que xp_sqlagent_notify
acontece. Mas acho que podemos presumir que esse procedimento estendido interage com o serviço do Agente e informa que houve uma alteração nesse trabalho e cronograma específicos. Ao executar um rastreamento do lado do servidor, podemos ver que, imediatamente, o SQL dinâmico a seguir é chamado pelo SQL Agent:
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 sysjobactivity
é atualizado imediatamente e sysjobschedules
é atualizado apenas em uma programação. Se mudarmos o novo horário para uma vez por dia, por exemplo,
@freq_type=4,
@freq_interval=1,
@freq_subday_type=1,
@freq_subday_interval=0,
@freq_relative_interval=0,
@freq_recurrence_factor=1,
Ainda vemos a atualização imediata sysjobactivity
conforme acima e, em seguida, outra atualização após a conclusão do trabalho. Várias atualizações vêm de segundo plano e outros threads no SQL Agent, por exemplo:
SQLAgent - Job Manager
SQLAgent - Update job activity
SQLAgent - Job invocation engine
SQLAgent - Schedule Saver
Um thread em segundo plano (o thread "Schedule Saver") finalmente aparece e é atualizado sysjobschedules
; da minha investigação inicial, parece que isso é a cada 20 minutos e só acontece sexp_sqlagent_notify
tiver sido chamado devido a uma alteração feita em um trabalho desde a última vez em que ele foi executado (não realizei nenhum teste adicional para ver o que acontece se um trabalho tiver sido executado). mudou e outro foi executado, se o segmento "Schedule Saver" atualizar os dois - eu suspeito que deve, mas deixará isso como um exercício para o leitor).
Não tenho certeza se o ciclo de 20 minutos é deslocado a partir do momento em que o SQL Agent é iniciado, ou da meia-noite ou de algo específico da máquina. Em duas instâncias diferentes no mesmo servidor físico, o segmento "Schedule Saver" foi atualizadosysjobschedules
, nas duas instâncias, quase exatamente no mesmo horário - 18:31:37 e 18:51:37 em um e 18:31:39 e 18:51:39 por outro. Não iniciei o SQL Server Agent ao mesmo tempo nesses servidores, mas existe a possibilidade remota de que os horários de início tenham sido 20 minutos de deslocamento. Duvido, mas não tenho tempo no momento para confirmar reiniciando o Agent em um deles e aguardando mais atualizações.
Sei quem o fez e quando aconteceu, porque coloquei um gatilho lá e o capturei, caso não conseguisse encontrá-lo no rastro ou o filtrasse 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
Dito isto, não é difícil capturar com um rastreamento padrão, esse mesmo aparece como DML não dinâmico:
UPDATE msdb.dbo.sysjobschedules
SET next_run_date = 20120817,
next_run_time = 20000
WHERE (job_id = 0xB87B329BFBF7BA40B30D9B27E0B120DE
and schedule_id = 8)
Se você deseja executar um rastreamento mais filtrado para rastrear esse comportamento ao longo do tempo (por exemplo, persistir na reinicialização do SQL Agent em vez de sob demanda), é possível executar um que tenha appname = 'SQLAgent - Schedule Saver'
...
Então, acho que se você quiser saber o próximo tempo de execução imediatamente, olhe sysjobactivity
, não sysjobschedules
. Esta tabela é diretamente atualizada pelo Agent ou por seus encadeamentos em segundo plano ("Atualizar atividade da tarefa", "Gerenciador de tarefas" e "Mecanismo de chamada de tarefas") à medida que a atividade acontece ou é notificada por xp_sqlagent_notify
.
Esteja ciente, no entanto, de que é muito fácil ocultar uma das tabelas - pois não há proteção contra a exclusão de dados dessas tabelas. (Portanto, se você decidir limpar, por exemplo, poderá remover facilmente todas as linhas desse trabalho da tabela de atividades.) Nesse caso, não tenho certeza de como o SQL Server Agent obtém ou salva a próxima data de execução. Talvez seja digno de mais investigação em uma data posterior, quando eu tiver algum tempo livre ...